blob: a110e07842212865ffaf1aa5f0ab4f995f5bbde1 [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 Perchesb6b38f72010-04-21 03:50:45 +0000142 cFYI(1, "can not send cmd %d while umounting",
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 Perchesb6b38f72010-04-21 03:50:45 +0000166 cFYI(1, "gave up waiting on reconnect in smb_init");
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 Perchesb6b38f72010-04-21 03:50:45 +0000194 cFYI(1, "reconnect tcon rc = %d", rc);
Jeff Layton9162ab22009-09-03 12:07:17 -0400195
196 if (rc)
197 goto out;
198
199 /*
200 * FIXME: check if wsize needs updated due to negotiated smb buffer
201 * size shrinking
202 */
203 atomic_inc(&tconInfoReconnectCount);
204
205 /* tell server Unix caps we support */
206 if (ses->capabilities & CAP_UNIX)
207 reset_cifs_unix_caps(0, tcon, NULL, NULL);
208
209 /*
210 * Removed call to reopen open files here. It is safer (and faster) to
211 * reopen files one at a time as needed in read and write.
212 *
213 * FIXME: what about file locks? don't we need to reclaim them ASAP?
214 */
215
216out:
217 /*
218 * Check if handle based operation so we know whether we can continue
219 * or not without returning to caller to reset file handle
220 */
221 switch (smb_command) {
222 case SMB_COM_READ_ANDX:
223 case SMB_COM_WRITE_ANDX:
224 case SMB_COM_CLOSE:
225 case SMB_COM_FIND_CLOSE2:
226 case SMB_COM_LOCKING_ANDX:
227 rc = -EAGAIN;
228 }
229
230 unload_nls(nls_codepage);
231 return rc;
232}
233
Steve Frenchad7a2922008-02-07 23:25:02 +0000234/* Allocate and return pointer to an SMB request buffer, and set basic
235 SMB information in the SMB header. If the return code is zero, this
236 function must have filled in request_buf pointer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237static int
Steve French96daf2b2011-05-27 04:34:02 +0000238small_smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000239 void **request_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240{
Jeff Laytonf5695992010-09-29 15:27:08 -0400241 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242
Jeff Layton9162ab22009-09-03 12:07:17 -0400243 rc = cifs_reconnect_tcon(tcon, smb_command);
Steve French790fe572007-07-07 19:25:05 +0000244 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245 return rc;
246
247 *request_buf = cifs_small_buf_get();
248 if (*request_buf == NULL) {
249 /* BB should we add a retry in here if not a writepage? */
250 return -ENOMEM;
251 }
252
Steve French63135e02007-07-17 17:34:02 +0000253 header_assemble((struct smb_hdr *) *request_buf, smb_command,
Steve Frenchc18c8422007-07-18 23:21:09 +0000254 tcon, wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255
Steve French790fe572007-07-07 19:25:05 +0000256 if (tcon != NULL)
257 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700258
Jeff Laytonf5695992010-09-29 15:27:08 -0400259 return 0;
Steve French5815449d2006-02-14 01:36:20 +0000260}
261
Steve French12b3b8f2006-02-09 21:12:47 +0000262int
Steve French50c2f752007-07-13 00:33:32 +0000263small_smb_init_no_tc(const int smb_command, const int wct,
Steve French96daf2b2011-05-27 04:34:02 +0000264 struct cifs_ses *ses, void **request_buf)
Steve French12b3b8f2006-02-09 21:12:47 +0000265{
266 int rc;
Steve French50c2f752007-07-13 00:33:32 +0000267 struct smb_hdr *buffer;
Steve French12b3b8f2006-02-09 21:12:47 +0000268
Steve French5815449d2006-02-14 01:36:20 +0000269 rc = small_smb_init(smb_command, wct, NULL, request_buf);
Steve French790fe572007-07-07 19:25:05 +0000270 if (rc)
Steve French12b3b8f2006-02-09 21:12:47 +0000271 return rc;
272
Steve French04fdabe2006-02-10 05:52:50 +0000273 buffer = (struct smb_hdr *)*request_buf;
Pavel Shilovsky88257362012-05-23 14:01:59 +0400274 buffer->Mid = get_next_mid(ses->server);
Steve French12b3b8f2006-02-09 21:12:47 +0000275 if (ses->capabilities & CAP_UNICODE)
276 buffer->Flags2 |= SMBFLG2_UNICODE;
Steve French04fdabe2006-02-10 05:52:50 +0000277 if (ses->capabilities & CAP_STATUS32)
Steve French12b3b8f2006-02-09 21:12:47 +0000278 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
279
280 /* uid, tid can stay at zero as set in header assemble */
281
Steve French50c2f752007-07-13 00:33:32 +0000282 /* BB add support for turning on the signing when
Steve French12b3b8f2006-02-09 21:12:47 +0000283 this function is used after 1st of session setup requests */
284
285 return rc;
286}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287
288/* If the return code is zero, this function must fill in request_buf pointer */
289static int
Steve French96daf2b2011-05-27 04:34:02 +0000290__smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400291 void **request_buf, void **response_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293 *request_buf = cifs_buf_get();
294 if (*request_buf == NULL) {
295 /* BB should we add a retry in here if not a writepage? */
296 return -ENOMEM;
297 }
298 /* Although the original thought was we needed the response buf for */
299 /* potential retries of smb operations it turns out we can determine */
300 /* from the mid flags when the request buffer can be resent without */
301 /* having to use a second distinct buffer for the response */
Steve French790fe572007-07-07 19:25:05 +0000302 if (response_buf)
Steve French50c2f752007-07-13 00:33:32 +0000303 *response_buf = *request_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304
305 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000306 wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307
Steve French790fe572007-07-07 19:25:05 +0000308 if (tcon != NULL)
309 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700310
Jeff Laytonf5695992010-09-29 15:27:08 -0400311 return 0;
312}
313
314/* If the return code is zero, this function must fill in request_buf pointer */
315static int
Steve French96daf2b2011-05-27 04:34:02 +0000316smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400317 void **request_buf, void **response_buf)
318{
319 int rc;
320
321 rc = cifs_reconnect_tcon(tcon, smb_command);
322 if (rc)
323 return rc;
324
325 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
326}
327
328static int
Steve French96daf2b2011-05-27 04:34:02 +0000329smb_init_no_reconnect(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400330 void **request_buf, void **response_buf)
331{
332 if (tcon->ses->need_reconnect || tcon->need_reconnect)
333 return -EHOSTDOWN;
334
335 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336}
337
Steve French50c2f752007-07-13 00:33:32 +0000338static int validate_t2(struct smb_t2_rsp *pSMB)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339{
Jeff Layton12df83c2011-01-20 13:36:51 -0500340 unsigned int total_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341
Jeff Layton12df83c2011-01-20 13:36:51 -0500342 /* check for plausible wct */
343 if (pSMB->hdr.WordCount < 10)
344 goto vt2_err;
345
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346 /* check for parm and data offset going beyond end of smb */
Jeff Layton12df83c2011-01-20 13:36:51 -0500347 if (get_unaligned_le16(&pSMB->t2_rsp.ParameterOffset) > 1024 ||
348 get_unaligned_le16(&pSMB->t2_rsp.DataOffset) > 1024)
349 goto vt2_err;
350
Jeff Layton12df83c2011-01-20 13:36:51 -0500351 total_size = get_unaligned_le16(&pSMB->t2_rsp.ParameterCount);
352 if (total_size >= 512)
353 goto vt2_err;
354
Jeff Laytonfd5707e2011-03-31 17:22:07 -0400355 /* check that bcc is at least as big as parms + data, and that it is
356 * less than negotiated smb buffer
357 */
Jeff Layton12df83c2011-01-20 13:36:51 -0500358 total_size += get_unaligned_le16(&pSMB->t2_rsp.DataCount);
359 if (total_size > get_bcc(&pSMB->hdr) ||
360 total_size >= CIFSMaxBufSize + MAX_CIFS_HDR_SIZE)
361 goto vt2_err;
362
363 return 0;
364vt2_err:
Steve French50c2f752007-07-13 00:33:32 +0000365 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 sizeof(struct smb_t2_rsp) + 16);
Jeff Layton12df83c2011-01-20 13:36:51 -0500367 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368}
Jeff Layton690c5222011-01-20 13:36:51 -0500369
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370int
Pavel Shilovsky286170a2012-05-25 10:43:58 +0400371CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372{
373 NEGOTIATE_REQ *pSMB;
374 NEGOTIATE_RSP *pSMBr;
375 int rc = 0;
376 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000377 int i;
Steve French50c2f752007-07-13 00:33:32 +0000378 struct TCP_Server_Info *server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 u16 count;
Steve French750d1152006-06-27 06:28:30 +0000380 unsigned int secFlags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381
Steve French790fe572007-07-07 19:25:05 +0000382 if (ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 server = ses->server;
384 else {
385 rc = -EIO;
386 return rc;
387 }
388 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
389 (void **) &pSMB, (void **) &pSMBr);
390 if (rc)
391 return rc;
Steve French750d1152006-06-27 06:28:30 +0000392
393 /* if any of auth flags (ie not sign or seal) are overriden use them */
Steve French790fe572007-07-07 19:25:05 +0000394 if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
Steve French762e5ab2007-06-28 18:41:42 +0000395 secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
Steve French750d1152006-06-27 06:28:30 +0000396 else /* if override flags set only sign/seal OR them with global auth */
Jeff Layton04912d62010-04-24 07:57:45 -0400397 secFlags = global_secflags | ses->overrideSecFlg;
Steve French750d1152006-06-27 06:28:30 +0000398
Joe Perchesb6b38f72010-04-21 03:50:45 +0000399 cFYI(1, "secFlags 0x%x", secFlags);
Steve Frenchf40c5622006-06-28 00:13:38 +0000400
Pavel Shilovsky88257362012-05-23 14:01:59 +0400401 pSMB->hdr.Mid = get_next_mid(server);
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000402 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
Steve Frencha0136892007-10-04 20:05:09 +0000403
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000404 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
Steve French254e55e2006-06-04 05:53:15 +0000405 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Steve Frencha0136892007-10-04 20:05:09 +0000406 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000407 cFYI(1, "Kerberos only mechanism, enable extended security");
Steve Frencha0136892007-10-04 20:05:09 +0000408 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Jeff Laytonb4d6fcf2011-01-07 11:30:28 -0500409 } else if ((secFlags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP)
Steve Frenchac683922009-05-06 04:16:04 +0000410 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
411 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_NTLMSSP) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000412 cFYI(1, "NTLMSSP only mechanism, enable extended security");
Steve Frenchac683922009-05-06 04:16:04 +0000413 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
414 }
Steve French50c2f752007-07-13 00:33:32 +0000415
Steve French39798772006-05-31 22:40:51 +0000416 count = 0;
Steve French50c2f752007-07-13 00:33:32 +0000417 for (i = 0; i < CIFS_NUM_PROT; i++) {
Steve French39798772006-05-31 22:40:51 +0000418 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
419 count += strlen(protocols[i].name) + 1;
420 /* null at end of source and target buffers anyway */
421 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000422 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 pSMB->ByteCount = cpu_to_le16(count);
424
425 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
426 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French50c2f752007-07-13 00:33:32 +0000427 if (rc != 0)
Steve French254e55e2006-06-04 05:53:15 +0000428 goto neg_err_exit;
429
Jeff Layton9bf67e52010-04-24 07:57:46 -0400430 server->dialect = le16_to_cpu(pSMBr->DialectIndex);
431 cFYI(1, "Dialect: %d", server->dialect);
Steve French254e55e2006-06-04 05:53:15 +0000432 /* Check wct = 1 error case */
Jeff Layton9bf67e52010-04-24 07:57:46 -0400433 if ((pSMBr->hdr.WordCount < 13) || (server->dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000434 /* core returns wct = 1, but we do not ask for core - otherwise
Steve French50c2f752007-07-13 00:33:32 +0000435 small wct just comes when dialect index is -1 indicating we
Steve French254e55e2006-06-04 05:53:15 +0000436 could not negotiate a common dialect */
437 rc = -EOPNOTSUPP;
438 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000439#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French790fe572007-07-07 19:25:05 +0000440 } else if ((pSMBr->hdr.WordCount == 13)
Jeff Layton9bf67e52010-04-24 07:57:46 -0400441 && ((server->dialect == LANMAN_PROT)
442 || (server->dialect == LANMAN2_PROT))) {
Steve Frenchb815f1e52006-10-02 05:53:29 +0000443 __s16 tmp;
Steve French50c2f752007-07-13 00:33:32 +0000444 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
Steve French254e55e2006-06-04 05:53:15 +0000445
Steve French790fe572007-07-07 19:25:05 +0000446 if ((secFlags & CIFSSEC_MAY_LANMAN) ||
Steve French750d1152006-06-27 06:28:30 +0000447 (secFlags & CIFSSEC_MAY_PLNTXT))
Steve French254e55e2006-06-04 05:53:15 +0000448 server->secType = LANMAN;
449 else {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000450 cERROR(1, "mount failed weak security disabled"
451 " in /proc/fs/cifs/SecurityFlags");
Steve French39798772006-05-31 22:40:51 +0000452 rc = -EOPNOTSUPP;
453 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000454 }
Pavel Shilovsky286170a2012-05-25 10:43:58 +0400455 server->sec_mode = le16_to_cpu(rsp->SecurityMode);
Pavel Shilovsky10b9b982012-03-20 12:55:09 +0300456 server->maxReq = min_t(unsigned int,
457 le16_to_cpu(rsp->MaxMpxCount),
458 cifs_max_pending);
Pavel Shilovsky45275782012-05-17 17:53:29 +0400459 set_credits(server, server->maxReq);
Jeff Laytonc974bef2011-10-11 06:41:32 -0400460 server->maxBuf = le16_to_cpu(rsp->MaxBufSize);
Steve Frencheca6acf2009-02-20 05:43:09 +0000461 server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
Steve French254e55e2006-06-04 05:53:15 +0000462 /* even though we do not use raw we might as well set this
463 accurately, in case we ever find a need for it */
Steve French790fe572007-07-07 19:25:05 +0000464 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
Steve Frencheca6acf2009-02-20 05:43:09 +0000465 server->max_rw = 0xFF00;
Steve French254e55e2006-06-04 05:53:15 +0000466 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
467 } else {
Steve Frencheca6acf2009-02-20 05:43:09 +0000468 server->max_rw = 0;/* do not need to use raw anyway */
Steve French254e55e2006-06-04 05:53:15 +0000469 server->capabilities = CAP_MPX_MODE;
470 }
Steve Frenchb815f1e52006-10-02 05:53:29 +0000471 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
Steve French1a70d652006-10-02 05:59:18 +0000472 if (tmp == -1) {
Steve French25ee4a92006-09-30 00:54:23 +0000473 /* OS/2 often does not set timezone therefore
474 * we must use server time to calc time zone.
Steve Frenchb815f1e52006-10-02 05:53:29 +0000475 * Could deviate slightly from the right zone.
476 * Smallest defined timezone difference is 15 minutes
477 * (i.e. Nepal). Rounding up/down is done to match
478 * this requirement.
Steve French25ee4a92006-09-30 00:54:23 +0000479 */
Steve Frenchb815f1e52006-10-02 05:53:29 +0000480 int val, seconds, remain, result;
Steve French25ee4a92006-09-30 00:54:23 +0000481 struct timespec ts, utc;
482 utc = CURRENT_TIME;
Jeff Laytonc4a2c082009-05-27 09:37:33 -0400483 ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
484 rsp->SrvTime.Time, 0);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000485 cFYI(1, "SrvTime %d sec since 1970 (utc: %d) diff: %d",
Steve French50c2f752007-07-13 00:33:32 +0000486 (int)ts.tv_sec, (int)utc.tv_sec,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000487 (int)(utc.tv_sec - ts.tv_sec));
Steve Frenchb815f1e52006-10-02 05:53:29 +0000488 val = (int)(utc.tv_sec - ts.tv_sec);
Andre Haupt8594c152007-08-30 20:18:41 +0000489 seconds = abs(val);
Steve French947a5062006-10-02 05:55:25 +0000490 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
Steve Frenchb815f1e52006-10-02 05:53:29 +0000491 remain = seconds % MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000492 if (remain >= (MIN_TZ_ADJ / 2))
Steve Frenchb815f1e52006-10-02 05:53:29 +0000493 result += MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000494 if (val < 0)
Steve Frenchad7a2922008-02-07 23:25:02 +0000495 result = -result;
Steve Frenchb815f1e52006-10-02 05:53:29 +0000496 server->timeAdj = result;
Steve French25ee4a92006-09-30 00:54:23 +0000497 } else {
Steve Frenchb815f1e52006-10-02 05:53:29 +0000498 server->timeAdj = (int)tmp;
499 server->timeAdj *= 60; /* also in seconds */
Steve French25ee4a92006-09-30 00:54:23 +0000500 }
Joe Perchesb6b38f72010-04-21 03:50:45 +0000501 cFYI(1, "server->timeAdj: %d seconds", server->timeAdj);
Steve French25ee4a92006-09-30 00:54:23 +0000502
Steve French39798772006-05-31 22:40:51 +0000503
Steve French254e55e2006-06-04 05:53:15 +0000504 /* BB get server time for time conversions and add
Steve French50c2f752007-07-13 00:33:32 +0000505 code to use it and timezone since this is not UTC */
Steve French39798772006-05-31 22:40:51 +0000506
Steve French50c2f752007-07-13 00:33:32 +0000507 if (rsp->EncryptionKeyLength ==
Steve French25ee4a92006-09-30 00:54:23 +0000508 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500509 memcpy(ses->server->cryptkey, rsp->EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000510 CIFS_CRYPTO_KEY_SIZE);
Steve French96daf2b2011-05-27 04:34:02 +0000511 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
Steve French254e55e2006-06-04 05:53:15 +0000512 rc = -EIO; /* need cryptkey unless plain text */
513 goto neg_err_exit;
514 }
Steve French39798772006-05-31 22:40:51 +0000515
Steve Frenchf19159d2010-04-21 04:12:10 +0000516 cFYI(1, "LANMAN negotiated");
Steve French254e55e2006-06-04 05:53:15 +0000517 /* we will not end up setting signing flags - as no signing
518 was in LANMAN and server did not return the flags on */
519 goto signing_check;
Steve French7c7b25b2006-06-01 19:20:10 +0000520#else /* weak security disabled */
Steve French790fe572007-07-07 19:25:05 +0000521 } else if (pSMBr->hdr.WordCount == 13) {
Steve Frenchf19159d2010-04-21 04:12:10 +0000522 cERROR(1, "mount failed, cifs module not built "
523 "with CIFS_WEAK_PW_HASH support");
Dan Carpenter8212cf72010-03-15 11:22:26 +0300524 rc = -EOPNOTSUPP;
Steve French7c7b25b2006-06-01 19:20:10 +0000525#endif /* WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000526 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000527 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000528 /* unknown wct */
529 rc = -EOPNOTSUPP;
530 goto neg_err_exit;
531 }
532 /* else wct == 17 NTLM */
Steve French96daf2b2011-05-27 04:34:02 +0000533 server->sec_mode = pSMBr->SecurityMode;
534 if ((server->sec_mode & SECMODE_USER) == 0)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000535 cFYI(1, "share mode security");
Steve French39798772006-05-31 22:40:51 +0000536
Steve French96daf2b2011-05-27 04:34:02 +0000537 if ((server->sec_mode & SECMODE_PW_ENCRYPT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000538#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French750d1152006-06-27 06:28:30 +0000539 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000540#endif /* CIFS_WEAK_PW_HASH */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000541 cERROR(1, "Server requests plain text password"
542 " but client support disabled");
Steve French9312f672006-06-04 22:21:07 +0000543
Steve French790fe572007-07-07 19:25:05 +0000544 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
Steve French254e55e2006-06-04 05:53:15 +0000545 server->secType = NTLMv2;
Steve French790fe572007-07-07 19:25:05 +0000546 else if (secFlags & CIFSSEC_MAY_NTLM)
Steve French254e55e2006-06-04 05:53:15 +0000547 server->secType = NTLM;
Steve French790fe572007-07-07 19:25:05 +0000548 else if (secFlags & CIFSSEC_MAY_NTLMV2)
Steve Frenchf40c5622006-06-28 00:13:38 +0000549 server->secType = NTLMv2;
Steve Frencha0136892007-10-04 20:05:09 +0000550 else if (secFlags & CIFSSEC_MAY_KRB5)
551 server->secType = Kerberos;
Steve Frenchac683922009-05-06 04:16:04 +0000552 else if (secFlags & CIFSSEC_MAY_NTLMSSP)
Steve Frenchf46c7232009-06-25 03:04:20 +0000553 server->secType = RawNTLMSSP;
Steve Frencha0136892007-10-04 20:05:09 +0000554 else if (secFlags & CIFSSEC_MAY_LANMAN)
555 server->secType = LANMAN;
Steve Frencha0136892007-10-04 20:05:09 +0000556 else {
557 rc = -EOPNOTSUPP;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000558 cERROR(1, "Invalid security type");
Steve Frencha0136892007-10-04 20:05:09 +0000559 goto neg_err_exit;
560 }
561 /* else ... any others ...? */
Steve French7c7b25b2006-06-01 19:20:10 +0000562
Steve French254e55e2006-06-04 05:53:15 +0000563 /* one byte, so no need to convert this or EncryptionKeyLen from
564 little endian */
Pavel Shilovsky10b9b982012-03-20 12:55:09 +0300565 server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount),
566 cifs_max_pending);
Pavel Shilovsky45275782012-05-17 17:53:29 +0400567 set_credits(server, server->maxReq);
Steve French254e55e2006-06-04 05:53:15 +0000568 /* probably no need to store and check maxvcs */
Jeff Laytonc974bef2011-10-11 06:41:32 -0400569 server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize);
Steve Frencheca6acf2009-02-20 05:43:09 +0000570 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000571 cFYI(DBG2, "Max buf = %d", ses->server->maxBuf);
Steve French254e55e2006-06-04 05:53:15 +0000572 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e52006-10-02 05:53:29 +0000573 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
574 server->timeAdj *= 60;
Steve French254e55e2006-06-04 05:53:15 +0000575 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500576 memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000577 CIFS_CRYPTO_KEY_SIZE);
Steve French07cc6cf2011-05-27 04:12:29 +0000578 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC ||
579 server->capabilities & CAP_EXTENDED_SECURITY) &&
580 (pSMBr->EncryptionKeyLength == 0)) {
Steve French254e55e2006-06-04 05:53:15 +0000581 /* decode security blob */
Jeff Layton820a8032011-05-04 08:05:26 -0400582 count = get_bcc(&pSMBr->hdr);
Jeff Laytone187e442007-10-16 17:10:44 +0000583 if (count < 16) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 rc = -EIO;
Jeff Laytone187e442007-10-16 17:10:44 +0000585 goto neg_err_exit;
586 }
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530587 spin_lock(&cifs_tcp_ses_lock);
Jeff Laytone7ddee92008-11-14 13:44:38 -0500588 if (server->srv_count > 1) {
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530589 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000590 if (memcmp(server->server_GUID,
591 pSMBr->u.extended_response.
592 GUID, 16) != 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000593 cFYI(1, "server UID changed");
Steve French254e55e2006-06-04 05:53:15 +0000594 memcpy(server->server_GUID,
Jeff Laytone187e442007-10-16 17:10:44 +0000595 pSMBr->u.extended_response.GUID,
596 16);
597 }
Jeff Laytone7ddee92008-11-14 13:44:38 -0500598 } else {
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530599 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000600 memcpy(server->server_GUID,
601 pSMBr->u.extended_response.GUID, 16);
Jeff Laytone7ddee92008-11-14 13:44:38 -0500602 }
Jeff Laytone187e442007-10-16 17:10:44 +0000603
604 if (count == 16) {
605 server->secType = RawNTLMSSP;
Steve French254e55e2006-06-04 05:53:15 +0000606 } else {
607 rc = decode_negTokenInit(pSMBr->u.extended_response.
Jeff Layton26efa0b2010-04-24 07:57:49 -0400608 SecurityBlob, count - 16,
609 server);
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000610 if (rc == 1)
Jeff Laytone5459372007-11-03 05:11:06 +0000611 rc = 0;
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000612 else
Steve French254e55e2006-06-04 05:53:15 +0000613 rc = -EINVAL;
Shirish Pargaonkar2b149f12010-09-18 22:02:18 -0500614 if (server->secType == Kerberos) {
615 if (!server->sec_kerberos &&
616 !server->sec_mskerberos)
617 rc = -EOPNOTSUPP;
618 } else if (server->secType == RawNTLMSSP) {
619 if (!server->sec_ntlmssp)
620 rc = -EOPNOTSUPP;
621 } else
622 rc = -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 }
Steve French96daf2b2011-05-27 04:34:02 +0000624 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
Steve French07cc6cf2011-05-27 04:12:29 +0000625 rc = -EIO; /* no crypt key only if plain text pwd */
626 goto neg_err_exit;
Steve French254e55e2006-06-04 05:53:15 +0000627 } else
628 server->capabilities &= ~CAP_EXTENDED_SECURITY;
629
Steve French6344a422006-06-12 04:18:35 +0000630#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French254e55e2006-06-04 05:53:15 +0000631signing_check:
Steve French6344a422006-06-12 04:18:35 +0000632#endif
Steve French762e5ab2007-06-28 18:41:42 +0000633 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
634 /* MUST_SIGN already includes the MAY_SIGN FLAG
635 so if this is zero it means that signing is disabled */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000636 cFYI(1, "Signing disabled");
Steve French96daf2b2011-05-27 04:34:02 +0000637 if (server->sec_mode & SECMODE_SIGN_REQUIRED) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000638 cERROR(1, "Server requires "
Jeff Layton7111d212007-10-16 16:50:25 +0000639 "packet signing to be enabled in "
Joe Perchesb6b38f72010-04-21 03:50:45 +0000640 "/proc/fs/cifs/SecurityFlags.");
Steve Frenchabb63d62007-10-18 02:58:40 +0000641 rc = -EOPNOTSUPP;
642 }
Steve French96daf2b2011-05-27 04:34:02 +0000643 server->sec_mode &=
Steve French254e55e2006-06-04 05:53:15 +0000644 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Steve French762e5ab2007-06-28 18:41:42 +0000645 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
646 /* signing required */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000647 cFYI(1, "Must sign - secFlags 0x%x", secFlags);
Steve French96daf2b2011-05-27 04:34:02 +0000648 if ((server->sec_mode &
Steve French762e5ab2007-06-28 18:41:42 +0000649 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000650 cERROR(1, "signing required but server lacks support");
Jeff38c10a12007-07-06 21:10:07 +0000651 rc = -EOPNOTSUPP;
Steve French762e5ab2007-06-28 18:41:42 +0000652 } else
Steve French96daf2b2011-05-27 04:34:02 +0000653 server->sec_mode |= SECMODE_SIGN_REQUIRED;
Steve French762e5ab2007-06-28 18:41:42 +0000654 } else {
655 /* signing optional ie CIFSSEC_MAY_SIGN */
Steve French96daf2b2011-05-27 04:34:02 +0000656 if ((server->sec_mode & SECMODE_SIGN_REQUIRED) == 0)
657 server->sec_mode &=
Steve French254e55e2006-06-04 05:53:15 +0000658 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 }
Steve French50c2f752007-07-13 00:33:32 +0000660
661neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700662 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000663
Joe Perchesb6b38f72010-04-21 03:50:45 +0000664 cFYI(1, "negprot rc %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 return rc;
666}
667
668int
Pavel Shilovsky2e6e02a2012-05-25 11:11:39 +0400669CIFSSMBTDis(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670{
671 struct smb_hdr *smb_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673
Joe Perchesb6b38f72010-04-21 03:50:45 +0000674 cFYI(1, "In tree disconnect");
Jeff Laytonf1987b42008-11-15 11:12:47 -0500675
676 /* BB: do we need to check this? These should never be NULL. */
677 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
678 return -EIO;
679
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 /*
Jeff Laytonf1987b42008-11-15 11:12:47 -0500681 * No need to return error on this operation if tid invalidated and
682 * closed on server already e.g. due to tcp session crashing. Also,
683 * the tcon is no longer on the list, so no need to take lock before
684 * checking this.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 */
Steve French268875b2009-06-25 00:29:21 +0000686 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
Steve French50c2f752007-07-13 00:33:32 +0000687 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688
Steve French50c2f752007-07-13 00:33:32 +0000689 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700690 (void **)&smb_buffer);
Jeff Laytonf1987b42008-11-15 11:12:47 -0500691 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 return rc;
Steve French133672e2007-11-13 22:41:37 +0000693
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400694 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)smb_buffer, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000696 cFYI(1, "Tree disconnect failed %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697
Steve French50c2f752007-07-13 00:33:32 +0000698 /* No need to return error on this operation if tid invalidated and
Jeff Laytonf1987b42008-11-15 11:12:47 -0500699 closed on server already e.g. due to tcp session crashing */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 if (rc == -EAGAIN)
701 rc = 0;
702
703 return rc;
704}
705
Jeff Layton766fdbb2011-01-11 07:24:21 -0500706/*
707 * This is a no-op for now. We're not really interested in the reply, but
708 * rather in the fact that the server sent one and that server->lstrp
709 * gets updated.
710 *
711 * FIXME: maybe we should consider checking that the reply matches request?
712 */
713static void
714cifs_echo_callback(struct mid_q_entry *mid)
715{
716 struct TCP_Server_Info *server = mid->callback_data;
717
718 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +0400719 add_credits(server, 1, CIFS_ECHO_OP);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500720}
721
722int
723CIFSSMBEcho(struct TCP_Server_Info *server)
724{
725 ECHO_REQ *smb;
726 int rc = 0;
Jeff Laytonfcc31cb2011-05-19 16:22:53 -0400727 struct kvec iov;
Jeff Laytonfec344e2012-09-18 16:20:35 -0700728 struct smb_rqst rqst = { .rq_iov = &iov,
729 .rq_nvec = 1 };
Jeff Layton766fdbb2011-01-11 07:24:21 -0500730
731 cFYI(1, "In echo request");
732
733 rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
734 if (rc)
735 return rc;
736
737 /* set up echo request */
Steve French5443d132011-03-13 05:08:25 +0000738 smb->hdr.Tid = 0xffff;
Jeff Layton99d86c8f2011-01-20 21:19:25 -0500739 smb->hdr.WordCount = 1;
740 put_unaligned_le16(1, &smb->EchoCount);
Jeff Layton820a8032011-05-04 08:05:26 -0400741 put_bcc(1, &smb->hdr);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500742 smb->Data[0] = 'a';
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000743 inc_rfc1001_len(smb, 3);
Jeff Laytonfcc31cb2011-05-19 16:22:53 -0400744 iov.iov_base = smb;
745 iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
Jeff Layton766fdbb2011-01-11 07:24:21 -0500746
Jeff Laytonfec344e2012-09-18 16:20:35 -0700747 rc = cifs_call_async(server, &rqst, NULL, cifs_echo_callback,
Pavel Shilovskya891f0f2012-05-23 16:14:34 +0400748 server, CIFS_ASYNC_OP | CIFS_ECHO_OP);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500749 if (rc)
750 cFYI(1, "Echo request failed: %d", rc);
751
752 cifs_small_buf_release(smb);
753
754 return rc;
755}
756
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757int
Pavel Shilovsky58c45c52012-05-25 10:54:49 +0400758CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 LOGOFF_ANDX_REQ *pSMB;
761 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762
Joe Perchesb6b38f72010-04-21 03:50:45 +0000763 cFYI(1, "In SMBLogoff for session disconnect");
Jeff Layton14fbf502008-11-14 13:53:46 -0500764
765 /*
766 * BB: do we need to check validity of ses and server? They should
767 * always be valid since we have an active reference. If not, that
768 * should probably be a BUG()
769 */
770 if (!ses || !ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 return -EIO;
772
Steve Frenchd7b619c2010-02-25 05:36:46 +0000773 mutex_lock(&ses->session_mutex);
Steve French3b795212008-11-13 19:45:32 +0000774 if (ses->need_reconnect)
775 goto session_already_dead; /* no need to send SMBlogoff if uid
776 already closed due to reconnect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
778 if (rc) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000779 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 return rc;
781 }
782
Pavel Shilovsky88257362012-05-23 14:01:59 +0400783 pSMB->hdr.Mid = get_next_mid(ses->server);
Steve French1982c342005-08-17 12:38:22 -0700784
Steve French96daf2b2011-05-27 04:34:02 +0000785 if (ses->server->sec_mode &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
787 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788
789 pSMB->hdr.Uid = ses->Suid;
790
791 pSMB->AndXCommand = 0xFF;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400792 rc = SendReceiveNoRsp(xid, ses, (char *) pSMB, 0);
Steve French3b795212008-11-13 19:45:32 +0000793session_already_dead:
Steve Frenchd7b619c2010-02-25 05:36:46 +0000794 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795
796 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000797 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 error */
799 if (rc == -EAGAIN)
800 rc = 0;
801 return rc;
802}
803
804int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400805CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
806 const char *fileName, __u16 type,
807 const struct nls_table *nls_codepage, int remap)
Steve French2d785a52007-07-15 01:48:57 +0000808{
809 TRANSACTION2_SPI_REQ *pSMB = NULL;
810 TRANSACTION2_SPI_RSP *pSMBr = NULL;
811 struct unlink_psx_rq *pRqD;
812 int name_len;
813 int rc = 0;
814 int bytes_returned = 0;
815 __u16 params, param_offset, offset, byte_count;
816
Joe Perchesb6b38f72010-04-21 03:50:45 +0000817 cFYI(1, "In POSIX delete");
Steve French2d785a52007-07-15 01:48:57 +0000818PsxDelete:
819 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
820 (void **) &pSMBr);
821 if (rc)
822 return rc;
823
824 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
825 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -0600826 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
827 PATH_MAX, nls_codepage, remap);
Steve French2d785a52007-07-15 01:48:57 +0000828 name_len++; /* trailing null */
829 name_len *= 2;
830 } else { /* BB add path length overrun check */
831 name_len = strnlen(fileName, PATH_MAX);
832 name_len++; /* trailing null */
833 strncpy(pSMB->FileName, fileName, name_len);
834 }
835
836 params = 6 + name_len;
837 pSMB->MaxParameterCount = cpu_to_le16(2);
838 pSMB->MaxDataCount = 0; /* BB double check this with jra */
839 pSMB->MaxSetupCount = 0;
840 pSMB->Reserved = 0;
841 pSMB->Flags = 0;
842 pSMB->Timeout = 0;
843 pSMB->Reserved2 = 0;
844 param_offset = offsetof(struct smb_com_transaction2_spi_req,
845 InformationLevel) - 4;
846 offset = param_offset + params;
847
848 /* Setup pointer to Request Data (inode type) */
849 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
850 pRqD->type = cpu_to_le16(type);
851 pSMB->ParameterOffset = cpu_to_le16(param_offset);
852 pSMB->DataOffset = cpu_to_le16(offset);
853 pSMB->SetupCount = 1;
854 pSMB->Reserved3 = 0;
855 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
856 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
857
858 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
859 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
860 pSMB->ParameterCount = cpu_to_le16(params);
861 pSMB->TotalParameterCount = pSMB->ParameterCount;
862 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
863 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000864 inc_rfc1001_len(pSMB, byte_count);
Steve French2d785a52007-07-15 01:48:57 +0000865 pSMB->ByteCount = cpu_to_le16(byte_count);
866 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
867 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000868 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000869 cFYI(1, "Posix delete returned %d", rc);
Steve French2d785a52007-07-15 01:48:57 +0000870 cifs_buf_release(pSMB);
871
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400872 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve French2d785a52007-07-15 01:48:57 +0000873
874 if (rc == -EAGAIN)
875 goto PsxDelete;
876
877 return rc;
878}
879
880int
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700881CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
882 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883{
884 DELETE_FILE_REQ *pSMB = NULL;
885 DELETE_FILE_RSP *pSMBr = NULL;
886 int rc = 0;
887 int bytes_returned;
888 int name_len;
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700889 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890
891DelFileRetry:
892 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
893 (void **) &pSMBr);
894 if (rc)
895 return rc;
896
897 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700898 name_len = cifsConvertToUTF16((__le16 *) pSMB->fileName, name,
899 PATH_MAX, cifs_sb->local_nls,
900 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 name_len++; /* trailing null */
902 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700903 } else { /* BB improve check for buffer overruns BB */
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700904 name_len = strnlen(name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 name_len++; /* trailing null */
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700906 strncpy(pSMB->fileName, name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907 }
908 pSMB->SearchAttributes =
909 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
910 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000911 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 pSMB->ByteCount = cpu_to_le16(name_len + 1);
913 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
914 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400915 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000916 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000917 cFYI(1, "Error in RMFile = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918
919 cifs_buf_release(pSMB);
920 if (rc == -EAGAIN)
921 goto DelFileRetry;
922
923 return rc;
924}
925
926int
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400927CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
928 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929{
930 DELETE_DIRECTORY_REQ *pSMB = NULL;
931 DELETE_DIRECTORY_RSP *pSMBr = NULL;
932 int rc = 0;
933 int bytes_returned;
934 int name_len;
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400935 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936
Joe Perchesb6b38f72010-04-21 03:50:45 +0000937 cFYI(1, "In CIFSSMBRmDir");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938RmDirRetry:
939 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
940 (void **) &pSMBr);
941 if (rc)
942 return rc;
943
944 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400945 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
946 PATH_MAX, cifs_sb->local_nls,
947 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948 name_len++; /* trailing null */
949 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700950 } else { /* BB improve check for buffer overruns BB */
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400951 name_len = strnlen(name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952 name_len++; /* trailing null */
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400953 strncpy(pSMB->DirName, name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954 }
955
956 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000957 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958 pSMB->ByteCount = cpu_to_le16(name_len + 1);
959 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
960 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400961 cifs_stats_inc(&tcon->stats.cifs_stats.num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000962 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000963 cFYI(1, "Error in RMDir = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964
965 cifs_buf_release(pSMB);
966 if (rc == -EAGAIN)
967 goto RmDirRetry;
968 return rc;
969}
970
971int
Pavel Shilovskyf4367202012-03-17 11:41:12 +0300972CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
973 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974{
975 int rc = 0;
976 CREATE_DIRECTORY_REQ *pSMB = NULL;
977 CREATE_DIRECTORY_RSP *pSMBr = NULL;
978 int bytes_returned;
979 int name_len;
Pavel Shilovskyf4367202012-03-17 11:41:12 +0300980 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981
Joe Perchesb6b38f72010-04-21 03:50:45 +0000982 cFYI(1, "In CIFSSMBMkDir");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983MkDirRetry:
984 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
985 (void **) &pSMBr);
986 if (rc)
987 return rc;
988
989 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -0600990 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
Pavel Shilovskyf4367202012-03-17 11:41:12 +0300991 PATH_MAX, cifs_sb->local_nls,
992 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993 name_len++; /* trailing null */
994 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700995 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 name_len = strnlen(name, PATH_MAX);
997 name_len++; /* trailing null */
998 strncpy(pSMB->DirName, name, name_len);
999 }
1000
1001 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001002 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 pSMB->ByteCount = cpu_to_le16(name_len + 1);
1004 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1005 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001006 cifs_stats_inc(&tcon->stats.cifs_stats.num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +00001007 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001008 cFYI(1, "Error in Mkdir = %d", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07001009
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 cifs_buf_release(pSMB);
1011 if (rc == -EAGAIN)
1012 goto MkDirRetry;
1013 return rc;
1014}
1015
Steve French2dd29d32007-04-23 22:07:35 +00001016int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001017CIFSPOSIXCreate(const unsigned int xid, struct cifs_tcon *tcon,
1018 __u32 posix_flags, __u64 mode, __u16 *netfid,
1019 FILE_UNIX_BASIC_INFO *pRetData, __u32 *pOplock,
1020 const char *name, const struct nls_table *nls_codepage,
1021 int remap)
Steve French2dd29d32007-04-23 22:07:35 +00001022{
1023 TRANSACTION2_SPI_REQ *pSMB = NULL;
1024 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1025 int name_len;
1026 int rc = 0;
1027 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001028 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +00001029 OPEN_PSX_REQ *pdata;
1030 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +00001031
Joe Perchesb6b38f72010-04-21 03:50:45 +00001032 cFYI(1, "In POSIX Create");
Steve French2dd29d32007-04-23 22:07:35 +00001033PsxCreat:
1034 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1035 (void **) &pSMBr);
1036 if (rc)
1037 return rc;
1038
1039 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1040 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001041 cifsConvertToUTF16((__le16 *) pSMB->FileName, name,
1042 PATH_MAX, nls_codepage, remap);
Steve French2dd29d32007-04-23 22:07:35 +00001043 name_len++; /* trailing null */
1044 name_len *= 2;
1045 } else { /* BB improve the check for buffer overruns BB */
1046 name_len = strnlen(name, PATH_MAX);
1047 name_len++; /* trailing null */
1048 strncpy(pSMB->FileName, name, name_len);
1049 }
1050
1051 params = 6 + name_len;
1052 count = sizeof(OPEN_PSX_REQ);
1053 pSMB->MaxParameterCount = cpu_to_le16(2);
1054 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1055 pSMB->MaxSetupCount = 0;
1056 pSMB->Reserved = 0;
1057 pSMB->Flags = 0;
1058 pSMB->Timeout = 0;
1059 pSMB->Reserved2 = 0;
1060 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001061 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001062 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001063 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001064 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001065 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001066 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001067 pdata->OpenFlags = cpu_to_le32(*pOplock);
1068 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1069 pSMB->DataOffset = cpu_to_le16(offset);
1070 pSMB->SetupCount = 1;
1071 pSMB->Reserved3 = 0;
1072 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1073 byte_count = 3 /* pad */ + params + count;
1074
1075 pSMB->DataCount = cpu_to_le16(count);
1076 pSMB->ParameterCount = cpu_to_le16(params);
1077 pSMB->TotalDataCount = pSMB->DataCount;
1078 pSMB->TotalParameterCount = pSMB->ParameterCount;
1079 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1080 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001081 inc_rfc1001_len(pSMB, byte_count);
Steve French2dd29d32007-04-23 22:07:35 +00001082 pSMB->ByteCount = cpu_to_le16(byte_count);
1083 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1084 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1085 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001086 cFYI(1, "Posix create returned %d", rc);
Steve French2dd29d32007-04-23 22:07:35 +00001087 goto psx_create_err;
1088 }
1089
Joe Perchesb6b38f72010-04-21 03:50:45 +00001090 cFYI(1, "copying inode info");
Steve French2dd29d32007-04-23 22:07:35 +00001091 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1092
Jeff Layton820a8032011-05-04 08:05:26 -04001093 if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) {
Steve French2dd29d32007-04-23 22:07:35 +00001094 rc = -EIO; /* bad smb */
1095 goto psx_create_err;
1096 }
1097
1098 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001099 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001100 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001101
Steve French2dd29d32007-04-23 22:07:35 +00001102 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001103 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001104 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1105 /* Let caller know file was created so we can set the mode. */
1106 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001107 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001108 *pOplock |= CIFS_CREATE_ACTION;
1109 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001110 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1111 pRetData->Type = cpu_to_le32(-1); /* unknown */
Joe Perchesb6b38f72010-04-21 03:50:45 +00001112 cFYI(DBG2, "unknown type");
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001113 } else {
Jeff Layton820a8032011-05-04 08:05:26 -04001114 if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001115 + sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001116 cERROR(1, "Open response data too small");
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001117 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001118 goto psx_create_err;
1119 }
Steve French50c2f752007-07-13 00:33:32 +00001120 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001121 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001122 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001123 }
Steve French2dd29d32007-04-23 22:07:35 +00001124
1125psx_create_err:
1126 cifs_buf_release(pSMB);
1127
Steve French65bc98b2009-07-10 15:27:25 +00001128 if (posix_flags & SMB_O_DIRECTORY)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001129 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixmkdirs);
Steve French65bc98b2009-07-10 15:27:25 +00001130 else
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001131 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixopens);
Steve French2dd29d32007-04-23 22:07:35 +00001132
1133 if (rc == -EAGAIN)
1134 goto PsxCreat;
1135
Steve French50c2f752007-07-13 00:33:32 +00001136 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001137}
1138
Steve Frencha9d02ad2005-08-24 23:06:05 -07001139static __u16 convert_disposition(int disposition)
1140{
1141 __u16 ofun = 0;
1142
1143 switch (disposition) {
1144 case FILE_SUPERSEDE:
1145 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1146 break;
1147 case FILE_OPEN:
1148 ofun = SMBOPEN_OAPPEND;
1149 break;
1150 case FILE_CREATE:
1151 ofun = SMBOPEN_OCREATE;
1152 break;
1153 case FILE_OPEN_IF:
1154 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1155 break;
1156 case FILE_OVERWRITE:
1157 ofun = SMBOPEN_OTRUNC;
1158 break;
1159 case FILE_OVERWRITE_IF:
1160 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1161 break;
1162 default:
Joe Perchesb6b38f72010-04-21 03:50:45 +00001163 cFYI(1, "unknown disposition %d", disposition);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001164 ofun = SMBOPEN_OAPPEND; /* regular open */
1165 }
1166 return ofun;
1167}
1168
Jeff Layton35fc37d2008-05-14 10:22:03 -07001169static int
1170access_flags_to_smbopen_mode(const int access_flags)
1171{
1172 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1173
1174 if (masked_flags == GENERIC_READ)
1175 return SMBOPEN_READ;
1176 else if (masked_flags == GENERIC_WRITE)
1177 return SMBOPEN_WRITE;
1178
1179 /* just go for read/write */
1180 return SMBOPEN_READWRITE;
1181}
1182
Steve Frencha9d02ad2005-08-24 23:06:05 -07001183int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001184SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001185 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001186 const int access_flags, const int create_options, __u16 *netfid,
1187 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001188 const struct nls_table *nls_codepage, int remap)
1189{
1190 int rc = -EACCES;
1191 OPENX_REQ *pSMB = NULL;
1192 OPENX_RSP *pSMBr = NULL;
1193 int bytes_returned;
1194 int name_len;
1195 __u16 count;
1196
1197OldOpenRetry:
1198 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1199 (void **) &pSMBr);
1200 if (rc)
1201 return rc;
1202
1203 pSMB->AndXCommand = 0xFF; /* none */
1204
1205 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1206 count = 1; /* account for one byte pad to word boundary */
1207 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001208 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1209 fileName, PATH_MAX, nls_codepage, remap);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001210 name_len++; /* trailing null */
1211 name_len *= 2;
1212 } else { /* BB improve check for buffer overruns BB */
1213 count = 0; /* no pad */
1214 name_len = strnlen(fileName, PATH_MAX);
1215 name_len++; /* trailing null */
1216 strncpy(pSMB->fileName, fileName, name_len);
1217 }
1218 if (*pOplock & REQ_OPLOCK)
1219 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001220 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001221 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001222
Steve Frencha9d02ad2005-08-24 23:06:05 -07001223 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001224 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001225 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1226 /* set file as system file if special file such
1227 as fifo and server expecting SFU style and
1228 no Unix extensions */
1229
Steve French790fe572007-07-07 19:25:05 +00001230 if (create_options & CREATE_OPTION_SPECIAL)
1231 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001232 else /* BB FIXME BB */
1233 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001234
Jeff Layton67750fb2008-05-09 22:28:02 +00001235 if (create_options & CREATE_OPTION_READONLY)
1236 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001237
1238 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001239/* pSMB->CreateOptions = cpu_to_le32(create_options &
1240 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001241 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001242
1243 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001244 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001245 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001246 inc_rfc1001_len(pSMB, count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001247
1248 pSMB->ByteCount = cpu_to_le16(count);
1249 /* long_op set to 1 to allow for oplock break timeouts */
1250 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001251 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001252 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001253 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001254 cFYI(1, "Error in Open = %d", rc);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001255 } else {
1256 /* BB verify if wct == 15 */
1257
Steve French582d21e2008-05-13 04:54:12 +00001258/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001259
1260 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1261 /* Let caller know file was created so we can set the mode. */
1262 /* Do we care about the CreateAction in any other cases? */
1263 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001264/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001265 *pOplock |= CIFS_CREATE_ACTION; */
1266 /* BB FIXME END */
1267
Steve French790fe572007-07-07 19:25:05 +00001268 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001269 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1270 pfile_info->LastAccessTime = 0; /* BB fixme */
1271 pfile_info->LastWriteTime = 0; /* BB fixme */
1272 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001273 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001274 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001275 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001276 pfile_info->AllocationSize =
1277 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1278 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001279 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001280 pfile_info->DeletePending = 0;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001281 }
1282 }
1283
1284 cifs_buf_release(pSMB);
1285 if (rc == -EAGAIN)
1286 goto OldOpenRetry;
1287 return rc;
1288}
1289
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001291CIFSSMBOpen(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001293 const int access_flags, const int create_options, __u16 *netfid,
1294 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001295 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296{
1297 int rc = -EACCES;
1298 OPEN_REQ *pSMB = NULL;
1299 OPEN_RSP *pSMBr = NULL;
1300 int bytes_returned;
1301 int name_len;
1302 __u16 count;
1303
1304openRetry:
1305 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1306 (void **) &pSMBr);
1307 if (rc)
1308 return rc;
1309
1310 pSMB->AndXCommand = 0xFF; /* none */
1311
1312 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1313 count = 1; /* account for one byte pad to word boundary */
1314 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001315 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1316 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317 name_len++; /* trailing null */
1318 name_len *= 2;
1319 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001320 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321 count = 0; /* no pad */
1322 name_len = strnlen(fileName, PATH_MAX);
1323 name_len++; /* trailing null */
1324 pSMB->NameLength = cpu_to_le16(name_len);
1325 strncpy(pSMB->fileName, fileName, name_len);
1326 }
1327 if (*pOplock & REQ_OPLOCK)
1328 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001329 else if (*pOplock & REQ_BATCHOPLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1332 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -07001333 /* set file as system file if special file such
1334 as fifo and server expecting SFU style and
1335 no Unix extensions */
Steve French790fe572007-07-07 19:25:05 +00001336 if (create_options & CREATE_OPTION_SPECIAL)
Steve Frencheda3c0292005-07-21 15:20:28 -07001337 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1338 else
1339 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Jeff Layton67750fb2008-05-09 22:28:02 +00001340
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341 /* XP does not handle ATTR_POSIX_SEMANTICS */
1342 /* but it helps speed up case sensitive checks for other
1343 servers such as Samba */
1344 if (tcon->ses->capabilities & CAP_UNIX)
1345 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1346
Jeff Layton67750fb2008-05-09 22:28:02 +00001347 if (create_options & CREATE_OPTION_READONLY)
1348 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1349
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1351 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -07001352 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001353 /* BB Expirement with various impersonation levels and verify */
1354 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355 pSMB->SecurityFlags =
1356 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1357
1358 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001359 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360
1361 pSMB->ByteCount = cpu_to_le16(count);
1362 /* long_op set to 1 to allow for oplock break timeouts */
1363 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001364 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001365 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001367 cFYI(1, "Error in Open = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368 } else {
Steve French09d1db52005-04-28 22:41:08 -07001369 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1371 /* Let caller know file was created so we can set the mode. */
1372 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001373 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve French50c2f752007-07-13 00:33:32 +00001374 *pOplock |= CIFS_CREATE_ACTION;
Steve French790fe572007-07-07 19:25:05 +00001375 if (pfile_info) {
Steve French61e74802008-12-03 00:57:54 +00001376 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1377 36 /* CreationTime to Attributes */);
1378 /* the file_info buf is endian converted by caller */
1379 pfile_info->AllocationSize = pSMBr->AllocationSize;
1380 pfile_info->EndOfFile = pSMBr->EndOfFile;
1381 pfile_info->NumberOfLinks = cpu_to_le32(1);
1382 pfile_info->DeletePending = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001385
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386 cifs_buf_release(pSMB);
1387 if (rc == -EAGAIN)
1388 goto openRetry;
1389 return rc;
1390}
1391
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001392/*
1393 * Discard any remaining data in the current SMB. To do this, we borrow the
1394 * current bigbuf.
1395 */
1396static int
1397cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1398{
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001399 unsigned int rfclen = get_rfc1002_length(server->smallbuf);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001400 int remaining = rfclen + 4 - server->total_read;
1401 struct cifs_readdata *rdata = mid->callback_data;
1402
1403 while (remaining > 0) {
1404 int length;
1405
1406 length = cifs_read_from_socket(server, server->bigbuf,
1407 min_t(unsigned int, remaining,
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001408 CIFSMaxBufSize + MAX_HEADER_SIZE(server)));
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001409 if (length < 0)
1410 return length;
1411 server->total_read += length;
1412 remaining -= length;
1413 }
1414
1415 dequeue_mid(mid, rdata->result);
1416 return 0;
1417}
1418
Pavel Shilovsky09a47072012-09-18 16:20:29 -07001419int
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001420cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1421{
1422 int length, len;
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001423 unsigned int data_offset, data_len;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001424 struct cifs_readdata *rdata = mid->callback_data;
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001425 char *buf = server->smallbuf;
1426 unsigned int buflen = get_rfc1002_length(buf) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001427
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001428 cFYI(1, "%s: mid=%llu offset=%llu bytes=%u", __func__,
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001429 mid->mid, rdata->offset, rdata->bytes);
1430
1431 /*
1432 * read the rest of READ_RSP header (sans Data array), or whatever we
1433 * can if there's not enough data. At this point, we've read down to
1434 * the Mid.
1435 */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001436 len = min_t(unsigned int, buflen, server->vals->read_rsp_size) -
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001437 HEADER_SIZE(server) + 1;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001438
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001439 rdata->iov[0].iov_base = buf + HEADER_SIZE(server) - 1;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001440 rdata->iov[0].iov_len = len;
1441
1442 length = cifs_readv_from_socket(server, rdata->iov, 1, len);
1443 if (length < 0)
1444 return length;
1445 server->total_read += length;
1446
1447 /* Was the SMB read successful? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001448 rdata->result = server->ops->map_error(buf, false);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001449 if (rdata->result != 0) {
1450 cFYI(1, "%s: server returned error %d", __func__,
1451 rdata->result);
1452 return cifs_readv_discard(server, mid);
1453 }
1454
1455 /* Is there enough to get to the rest of the READ_RSP header? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001456 if (server->total_read < server->vals->read_rsp_size) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001457 cFYI(1, "%s: server returned short header. got=%u expected=%zu",
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001458 __func__, server->total_read,
1459 server->vals->read_rsp_size);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001460 rdata->result = -EIO;
1461 return cifs_readv_discard(server, mid);
1462 }
1463
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001464 data_offset = server->ops->read_data_offset(buf) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001465 if (data_offset < server->total_read) {
1466 /*
1467 * win2k8 sometimes sends an offset of 0 when the read
1468 * is beyond the EOF. Treat it as if the data starts just after
1469 * the header.
1470 */
1471 cFYI(1, "%s: data offset (%u) inside read response header",
1472 __func__, data_offset);
1473 data_offset = server->total_read;
1474 } else if (data_offset > MAX_CIFS_SMALL_BUFFER_SIZE) {
1475 /* data_offset is beyond the end of smallbuf */
1476 cFYI(1, "%s: data offset (%u) beyond end of smallbuf",
1477 __func__, data_offset);
1478 rdata->result = -EIO;
1479 return cifs_readv_discard(server, mid);
1480 }
1481
1482 cFYI(1, "%s: total_read=%u data_offset=%u", __func__,
1483 server->total_read, data_offset);
1484
1485 len = data_offset - server->total_read;
1486 if (len > 0) {
1487 /* read any junk before data into the rest of smallbuf */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001488 rdata->iov[0].iov_base = buf + server->total_read;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001489 rdata->iov[0].iov_len = len;
1490 length = cifs_readv_from_socket(server, rdata->iov, 1, len);
1491 if (length < 0)
1492 return length;
1493 server->total_read += length;
1494 }
1495
1496 /* set up first iov for signature check */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001497 rdata->iov[0].iov_base = buf;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001498 rdata->iov[0].iov_len = server->total_read;
1499 cFYI(1, "0: iov_base=%p iov_len=%zu",
1500 rdata->iov[0].iov_base, rdata->iov[0].iov_len);
1501
1502 /* how much data is in the response? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001503 data_len = server->ops->read_data_length(buf);
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001504 if (data_offset + data_len > buflen) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001505 /* data_len is corrupt -- discard frame */
1506 rdata->result = -EIO;
1507 return cifs_readv_discard(server, mid);
1508 }
1509
1510 /* marshal up the page array */
Jeff Layton3cf003c2012-07-11 09:09:36 -04001511 cifs_kmap_lock();
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001512 len = rdata->marshal_iov(rdata, data_len);
Jeff Layton3cf003c2012-07-11 09:09:36 -04001513 cifs_kmap_unlock();
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001514 data_len -= len;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001515
1516 /* issue the read if we have any iovecs left to fill */
1517 if (rdata->nr_iov > 1) {
1518 length = cifs_readv_from_socket(server, &rdata->iov[1],
1519 rdata->nr_iov - 1, len);
1520 if (length < 0)
1521 return length;
1522 server->total_read += length;
1523 } else {
1524 length = 0;
1525 }
1526
1527 rdata->bytes = length;
1528
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001529 cFYI(1, "total_read=%u buflen=%u remaining=%u", server->total_read,
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001530 buflen, data_len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001531
1532 /* discard anything left over */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001533 if (server->total_read < buflen)
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001534 return cifs_readv_discard(server, mid);
1535
1536 dequeue_mid(mid, false);
1537 return length;
1538}
1539
1540static void
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001541cifs_readv_callback(struct mid_q_entry *mid)
1542{
1543 struct cifs_readdata *rdata = mid->callback_data;
1544 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1545 struct TCP_Server_Info *server = tcon->ses->server;
Jeff Laytonbf5ea0e2012-09-18 16:20:34 -07001546 struct smb_rqst rqst = { .rq_iov = rdata->iov,
1547 .rq_nvec = rdata->nr_iov };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001548
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001549 cFYI(1, "%s: mid=%llu state=%d result=%d bytes=%u", __func__,
1550 mid->mid, mid->mid_state, rdata->result, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001551
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001552 switch (mid->mid_state) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001553 case MID_RESPONSE_RECEIVED:
1554 /* result already set, check signature */
1555 if (server->sec_mode &
1556 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
Steve French985e4ff02012-08-03 09:42:45 -05001557 int rc = 0;
1558
Jeff Laytonbf5ea0e2012-09-18 16:20:34 -07001559 rc = cifs_verify_signature(&rqst, server,
1560 mid->sequence_number + 1);
Steve French985e4ff02012-08-03 09:42:45 -05001561 if (rc)
1562 cERROR(1, "SMB signature verification returned "
1563 "error = %d", rc);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001564 }
1565 /* FIXME: should this be counted toward the initiating task? */
1566 task_io_account_read(rdata->bytes);
1567 cifs_stats_bytes_read(tcon, rdata->bytes);
1568 break;
1569 case MID_REQUEST_SUBMITTED:
1570 case MID_RETRY_NEEDED:
1571 rdata->result = -EAGAIN;
1572 break;
1573 default:
1574 rdata->result = -EIO;
1575 }
1576
Jeff Laytonda472fc2012-03-23 14:40:53 -04001577 queue_work(cifsiod_wq, &rdata->work);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001578 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04001579 add_credits(server, 1, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001580}
1581
1582/* cifs_async_readv - send an async write, and set up mid to handle result */
1583int
1584cifs_async_readv(struct cifs_readdata *rdata)
1585{
1586 int rc;
1587 READ_REQ *smb = NULL;
1588 int wct;
1589 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
Jeff Laytonfec344e2012-09-18 16:20:35 -07001590 struct smb_rqst rqst = { .rq_iov = rdata->iov,
1591 .rq_nvec = 1 };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001592
1593 cFYI(1, "%s: offset=%llu bytes=%u", __func__,
1594 rdata->offset, rdata->bytes);
1595
1596 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1597 wct = 12;
1598 else {
1599 wct = 10; /* old style read */
1600 if ((rdata->offset >> 32) > 0) {
1601 /* can not handle this big offset for old */
1602 return -EIO;
1603 }
1604 }
1605
1606 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **)&smb);
1607 if (rc)
1608 return rc;
1609
1610 smb->hdr.Pid = cpu_to_le16((__u16)rdata->pid);
1611 smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16));
1612
1613 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07001614 smb->Fid = rdata->cfile->fid.netfid;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001615 smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF);
1616 if (wct == 12)
1617 smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32);
1618 smb->Remaining = 0;
1619 smb->MaxCount = cpu_to_le16(rdata->bytes & 0xFFFF);
1620 smb->MaxCountHigh = cpu_to_le32(rdata->bytes >> 16);
1621 if (wct == 12)
1622 smb->ByteCount = 0;
1623 else {
1624 /* old style read */
1625 struct smb_com_readx_req *smbr =
1626 (struct smb_com_readx_req *)smb;
1627 smbr->ByteCount = 0;
1628 }
1629
1630 /* 4 for RFC1001 length + 1 for BCC */
1631 rdata->iov[0].iov_base = smb;
1632 rdata->iov[0].iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
1633
Jeff Layton6993f742012-05-16 07:13:17 -04001634 kref_get(&rdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07001635 rc = cifs_call_async(tcon->ses->server, &rqst, cifs_readv_receive,
1636 cifs_readv_callback, rdata, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001637
1638 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001639 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Jeff Layton6993f742012-05-16 07:13:17 -04001640 else
1641 kref_put(&rdata->refcount, cifs_readdata_release);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001642
1643 cifs_small_buf_release(smb);
1644 return rc;
1645}
1646
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001648CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
1649 unsigned int *nbytes, char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650{
1651 int rc = -EACCES;
1652 READ_REQ *pSMB = NULL;
1653 READ_RSP *pSMBr = NULL;
1654 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001655 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001656 int resp_buf_type = 0;
1657 struct kvec iov[1];
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001658 __u32 pid = io_parms->pid;
1659 __u16 netfid = io_parms->netfid;
1660 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001661 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001662 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663
Joe Perchesb6b38f72010-04-21 03:50:45 +00001664 cFYI(1, "Reading %d bytes on fid %d", count, netfid);
Steve French790fe572007-07-07 19:25:05 +00001665 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001666 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001667 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001668 wct = 10; /* old style read */
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001669 if ((offset >> 32) > 0) {
Steve French4c3130e2008-12-09 00:28:16 +00001670 /* can not handle this big offset for old */
1671 return -EIO;
1672 }
1673 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674
1675 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001676 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677 if (rc)
1678 return rc;
1679
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001680 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1681 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1682
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683 /* tcon and ses pointer are checked in smb_init */
1684 if (tcon->ses->server == NULL)
1685 return -ECONNABORTED;
1686
Steve Frenchec637e32005-12-12 20:53:18 -08001687 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001688 pSMB->Fid = netfid;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001689 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001690 if (wct == 12)
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001691 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001692
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693 pSMB->Remaining = 0;
1694 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1695 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001696 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001697 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1698 else {
1699 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001700 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001701 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001702 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001703 }
Steve Frenchec637e32005-12-12 20:53:18 -08001704
1705 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001706 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve Frencha761ac52007-10-18 21:45:27 +00001707 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Jeff Layton77499812011-01-11 07:24:23 -05001708 &resp_buf_type, CIFS_LOG_ERROR);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001709 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001710 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001712 cERROR(1, "Send error in read = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713 } else {
1714 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1715 data_length = data_length << 16;
1716 data_length += le16_to_cpu(pSMBr->DataLength);
1717 *nbytes = data_length;
1718
1719 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001720 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721 || (data_length > count)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001722 cFYI(1, "bad length %d for count %d",
1723 data_length, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724 rc = -EIO;
1725 *nbytes = 0;
1726 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001727 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001728 le16_to_cpu(pSMBr->DataOffset);
1729/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001730 cERROR(1, "Faulting on read rc = %d",rc);
Steve French50c2f752007-07-13 00:33:32 +00001731 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001732 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001733 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001734 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735 }
1736 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737
Steve French4b8f9302006-02-26 16:41:18 +00001738/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001739 if (*buf) {
1740 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001741 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001742 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001743 cifs_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001744 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001745 /* return buffer to caller to free */
1746 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001747 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001748 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001749 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001750 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001751 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001752
1753 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001754 since file handle passed in no longer valid */
1755 return rc;
1756}
1757
Steve Frenchec637e32005-12-12 20:53:18 -08001758
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001760CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001761 unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001762 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001763{
1764 int rc = -EACCES;
1765 WRITE_REQ *pSMB = NULL;
1766 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001767 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001768 __u32 bytes_sent;
1769 __u16 byte_count;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001770 __u32 pid = io_parms->pid;
1771 __u16 netfid = io_parms->netfid;
1772 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001773 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001774 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001775
Steve Frencha24e2d72010-04-03 17:20:21 +00001776 *nbytes = 0;
1777
Joe Perchesb6b38f72010-04-21 03:50:45 +00001778 /* cFYI(1, "write at %lld %d bytes", offset, count);*/
Steve French790fe572007-07-07 19:25:05 +00001779 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001780 return -ECONNABORTED;
1781
Steve French790fe572007-07-07 19:25:05 +00001782 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001783 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001784 else {
Steve French1c955182005-08-30 20:58:07 -07001785 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001786 if ((offset >> 32) > 0) {
1787 /* can not handle big offset for old srv */
1788 return -EIO;
1789 }
1790 }
Steve French1c955182005-08-30 20:58:07 -07001791
1792 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793 (void **) &pSMBr);
1794 if (rc)
1795 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001796
1797 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1798 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1799
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800 /* tcon and ses pointer are checked in smb_init */
1801 if (tcon->ses->server == NULL)
1802 return -ECONNABORTED;
1803
1804 pSMB->AndXCommand = 0xFF; /* none */
1805 pSMB->Fid = netfid;
1806 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001807 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001808 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001809
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810 pSMB->Reserved = 0xFFFFFFFF;
1811 pSMB->WriteMode = 0;
1812 pSMB->Remaining = 0;
1813
Steve French50c2f752007-07-13 00:33:32 +00001814 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815 can send more if LARGE_WRITE_X capability returned by the server and if
1816 our buffer is big enough or if we convert to iovecs on socket writes
1817 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001818 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1820 } else {
1821 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1822 & ~0xFF;
1823 }
1824
1825 if (bytes_sent > count)
1826 bytes_sent = count;
1827 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001828 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001829 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001830 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001831 else if (ubuf) {
1832 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001833 cifs_buf_release(pSMB);
1834 return -EFAULT;
1835 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001836 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837 /* No buffer */
1838 cifs_buf_release(pSMB);
1839 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001840 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001841 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001842 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001843 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001844 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001845
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1847 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001848 inc_rfc1001_len(pSMB, byte_count);
Steve French1c955182005-08-30 20:58:07 -07001849
Steve French790fe572007-07-07 19:25:05 +00001850 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001851 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001852 else { /* old style write has byte count 4 bytes earlier
1853 so 4 bytes pad */
1854 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001855 (struct smb_com_writex_req *)pSMB;
1856 pSMBW->ByteCount = cpu_to_le16(byte_count);
1857 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858
1859 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1860 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001861 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00001863 cFYI(1, "Send error in write = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864 } else {
1865 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1866 *nbytes = (*nbytes) << 16;
1867 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301868
1869 /*
1870 * Mask off high 16 bits when bytes written as returned by the
1871 * server is greater than bytes requested by the client. Some
1872 * OS/2 servers are known to set incorrect CountHigh values.
1873 */
1874 if (*nbytes > count)
1875 *nbytes &= 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876 }
1877
1878 cifs_buf_release(pSMB);
1879
Steve French50c2f752007-07-13 00:33:32 +00001880 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881 since file handle passed in no longer valid */
1882
1883 return rc;
1884}
1885
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001886void
1887cifs_writedata_release(struct kref *refcount)
1888{
1889 struct cifs_writedata *wdata = container_of(refcount,
1890 struct cifs_writedata, refcount);
1891
1892 if (wdata->cfile)
1893 cifsFileInfo_put(wdata->cfile);
1894
1895 kfree(wdata);
1896}
1897
1898/*
1899 * Write failed with a retryable error. Resend the write request. It's also
1900 * possible that the page was redirtied so re-clean the page.
1901 */
1902static void
1903cifs_writev_requeue(struct cifs_writedata *wdata)
1904{
1905 int i, rc;
1906 struct inode *inode = wdata->cfile->dentry->d_inode;
Pavel Shilovskyc9de5c82012-09-18 16:20:29 -07001907 struct TCP_Server_Info *server;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001908
1909 for (i = 0; i < wdata->nr_pages; i++) {
1910 lock_page(wdata->pages[i]);
1911 clear_page_dirty_for_io(wdata->pages[i]);
1912 }
1913
1914 do {
Pavel Shilovskyc9de5c82012-09-18 16:20:29 -07001915 server = tlink_tcon(wdata->cfile->tlink)->ses->server;
1916 rc = server->ops->async_writev(wdata);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001917 } while (rc == -EAGAIN);
1918
1919 for (i = 0; i < wdata->nr_pages; i++) {
1920 if (rc != 0)
1921 SetPageError(wdata->pages[i]);
1922 unlock_page(wdata->pages[i]);
1923 }
1924
1925 mapping_set_error(inode->i_mapping, rc);
1926 kref_put(&wdata->refcount, cifs_writedata_release);
1927}
1928
Jeff Laytonc2e87642012-03-23 14:40:55 -04001929void
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001930cifs_writev_complete(struct work_struct *work)
1931{
1932 struct cifs_writedata *wdata = container_of(work,
1933 struct cifs_writedata, work);
1934 struct inode *inode = wdata->cfile->dentry->d_inode;
1935 int i = 0;
1936
1937 if (wdata->result == 0) {
Jeff Layton597b0272012-03-23 14:40:56 -04001938 spin_lock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001939 cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
Jeff Layton597b0272012-03-23 14:40:56 -04001940 spin_unlock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001941 cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
1942 wdata->bytes);
1943 } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
1944 return cifs_writev_requeue(wdata);
1945
1946 for (i = 0; i < wdata->nr_pages; i++) {
1947 struct page *page = wdata->pages[i];
1948 if (wdata->result == -EAGAIN)
1949 __set_page_dirty_nobuffers(page);
1950 else if (wdata->result < 0)
1951 SetPageError(page);
1952 end_page_writeback(page);
1953 page_cache_release(page);
1954 }
1955 if (wdata->result != -EAGAIN)
1956 mapping_set_error(inode->i_mapping, wdata->result);
1957 kref_put(&wdata->refcount, cifs_writedata_release);
1958}
1959
1960struct cifs_writedata *
Jeff Laytonc2e87642012-03-23 14:40:55 -04001961cifs_writedata_alloc(unsigned int nr_pages, work_func_t complete)
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001962{
1963 struct cifs_writedata *wdata;
1964
1965 /* this would overflow */
1966 if (nr_pages == 0) {
1967 cERROR(1, "%s: called with nr_pages == 0!", __func__);
1968 return NULL;
1969 }
1970
1971 /* writedata + number of page pointers */
1972 wdata = kzalloc(sizeof(*wdata) +
1973 sizeof(struct page *) * (nr_pages - 1), GFP_NOFS);
1974 if (wdata != NULL) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001975 kref_init(&wdata->refcount);
Jeff Laytonda82f7e2012-03-23 14:40:56 -04001976 INIT_LIST_HEAD(&wdata->list);
1977 init_completion(&wdata->done);
1978 INIT_WORK(&wdata->work, complete);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001979 }
1980 return wdata;
1981}
1982
1983/*
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001984 * Check the mid_state and signature on received buffer (if any), and queue the
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001985 * workqueue completion task.
1986 */
1987static void
1988cifs_writev_callback(struct mid_q_entry *mid)
1989{
1990 struct cifs_writedata *wdata = mid->callback_data;
Steve French96daf2b2011-05-27 04:34:02 +00001991 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001992 unsigned int written;
1993 WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
1994
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001995 switch (mid->mid_state) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001996 case MID_RESPONSE_RECEIVED:
1997 wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
1998 if (wdata->result != 0)
1999 break;
2000
2001 written = le16_to_cpu(smb->CountHigh);
2002 written <<= 16;
2003 written += le16_to_cpu(smb->Count);
2004 /*
2005 * Mask off high 16 bits when bytes written as returned
2006 * by the server is greater than bytes requested by the
2007 * client. OS/2 servers are known to set incorrect
2008 * CountHigh values.
2009 */
2010 if (written > wdata->bytes)
2011 written &= 0xFFFF;
2012
2013 if (written < wdata->bytes)
2014 wdata->result = -ENOSPC;
2015 else
2016 wdata->bytes = written;
2017 break;
2018 case MID_REQUEST_SUBMITTED:
2019 case MID_RETRY_NEEDED:
2020 wdata->result = -EAGAIN;
2021 break;
2022 default:
2023 wdata->result = -EIO;
2024 break;
2025 }
2026
Jeff Laytonda472fc2012-03-23 14:40:53 -04002027 queue_work(cifsiod_wq, &wdata->work);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002028 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002029 add_credits(tcon->ses->server, 1, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002030}
2031
2032/* cifs_async_writev - send an async write, and set up mid to handle result */
2033int
2034cifs_async_writev(struct cifs_writedata *wdata)
2035{
Jeff Laytoneddb0792012-09-18 16:20:35 -07002036 int rc = -EACCES;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002037 WRITE_REQ *smb = NULL;
2038 int wct;
Steve French96daf2b2011-05-27 04:34:02 +00002039 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytoneddb0792012-09-18 16:20:35 -07002040 struct kvec iov;
Jeff Laytonfec344e2012-09-18 16:20:35 -07002041 struct smb_rqst rqst = { };
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002042
2043 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
2044 wct = 14;
2045 } else {
2046 wct = 12;
2047 if (wdata->offset >> 32 > 0) {
2048 /* can not handle big offset for old srv */
2049 return -EIO;
2050 }
2051 }
2052
2053 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
2054 if (rc)
2055 goto async_writev_out;
2056
Jeff Laytonfe5f5d22012-03-23 14:40:55 -04002057 smb->hdr.Pid = cpu_to_le16((__u16)wdata->pid);
2058 smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16));
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002059
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002060 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07002061 smb->Fid = wdata->cfile->fid.netfid;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002062 smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
2063 if (wct == 14)
2064 smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
2065 smb->Reserved = 0xFFFFFFFF;
2066 smb->WriteMode = 0;
2067 smb->Remaining = 0;
2068
2069 smb->DataOffset =
2070 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
2071
2072 /* 4 for RFC1001 length + 1 for BCC */
Jeff Laytoneddb0792012-09-18 16:20:35 -07002073 iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4 + 1;
2074 iov.iov_base = smb;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002075
Jeff Laytoneddb0792012-09-18 16:20:35 -07002076 rqst.rq_iov = &iov;
2077 rqst.rq_nvec = 1;
2078 rqst.rq_pages = wdata->pages;
2079 rqst.rq_npages = wdata->nr_pages;
2080 rqst.rq_pagesz = wdata->pagesz;
2081 rqst.rq_tailsz = wdata->tailsz;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002082
2083 cFYI(1, "async write at %llu %u bytes", wdata->offset, wdata->bytes);
2084
2085 smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
2086 smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16);
2087
2088 if (wct == 14) {
2089 inc_rfc1001_len(&smb->hdr, wdata->bytes + 1);
2090 put_bcc(wdata->bytes + 1, &smb->hdr);
2091 } else {
2092 /* wct == 12 */
2093 struct smb_com_writex_req *smbw =
2094 (struct smb_com_writex_req *)smb;
2095 inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
2096 put_bcc(wdata->bytes + 5, &smbw->hdr);
Jeff Laytoneddb0792012-09-18 16:20:35 -07002097 iov.iov_len += 4; /* pad bigger by four bytes */
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002098 }
2099
2100 kref_get(&wdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07002101 rc = cifs_call_async(tcon->ses->server, &rqst, NULL,
2102 cifs_writev_callback, wdata, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002103
2104 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002105 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002106 else
2107 kref_put(&wdata->refcount, cifs_writedata_release);
2108
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002109async_writev_out:
2110 cifs_small_buf_release(smb);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002111 return rc;
2112}
2113
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002114int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002115CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
Pavel Shilovskyba9ad7252012-09-18 16:20:30 -07002116 unsigned int *nbytes, struct kvec *iov, int n_vec)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002117{
2118 int rc = -EACCES;
2119 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08002120 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002121 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08002122 int resp_buf_type = 0;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002123 __u32 pid = io_parms->pid;
2124 __u16 netfid = io_parms->netfid;
2125 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00002126 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002127 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002128
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04002129 *nbytes = 0;
2130
Joe Perchesb6b38f72010-04-21 03:50:45 +00002131 cFYI(1, "write2 at %lld %d bytes", (long long)offset, count);
Steve Frenchff7feac2005-11-15 16:45:16 -08002132
Steve French4c3130e2008-12-09 00:28:16 +00002133 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07002134 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00002135 } else {
Steve French8cc64c62005-10-03 13:49:43 -07002136 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00002137 if ((offset >> 32) > 0) {
2138 /* can not handle big offset for old srv */
2139 return -EIO;
2140 }
2141 }
Steve French8cc64c62005-10-03 13:49:43 -07002142 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002143 if (rc)
2144 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002145
2146 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
2147 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
2148
Linus Torvalds1da177e2005-04-16 15:20:36 -07002149 /* tcon and ses pointer are checked in smb_init */
2150 if (tcon->ses->server == NULL)
2151 return -ECONNABORTED;
2152
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002153 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002154 pSMB->Fid = netfid;
2155 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00002156 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002157 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002158 pSMB->Reserved = 0xFFFFFFFF;
2159 pSMB->WriteMode = 0;
2160 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002161
Linus Torvalds1da177e2005-04-16 15:20:36 -07002162 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00002163 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002164
Steve French3e844692005-10-03 13:37:24 -07002165 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
2166 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002167 /* header + 1 byte pad */
2168 smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
Steve French790fe572007-07-07 19:25:05 +00002169 if (wct == 14)
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002170 inc_rfc1001_len(pSMB, count + 1);
Steve French8cc64c62005-10-03 13:49:43 -07002171 else /* wct == 12 */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002172 inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
Steve French790fe572007-07-07 19:25:05 +00002173 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002174 pSMB->ByteCount = cpu_to_le16(count + 1);
2175 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00002176 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07002177 (struct smb_com_writex_req *)pSMB;
2178 pSMBW->ByteCount = cpu_to_le16(count + 5);
2179 }
Steve French3e844692005-10-03 13:37:24 -07002180 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00002181 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08002182 iov[0].iov_len = smb_hdr_len + 4;
2183 else /* wct == 12 pad bigger by four bytes */
2184 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00002185
Steve French3e844692005-10-03 13:37:24 -07002186
Pavel Shilovskyba9ad7252012-09-18 16:20:30 -07002187 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002188 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002189 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002190 cFYI(1, "Send error Write2 = %d", rc);
Steve French790fe572007-07-07 19:25:05 +00002191 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08002192 /* presumably this can not happen, but best to be safe */
2193 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002194 } else {
Steve Frenchad7a2922008-02-07 23:25:02 +00002195 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002196 *nbytes = le16_to_cpu(pSMBr->CountHigh);
2197 *nbytes = (*nbytes) << 16;
2198 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05302199
2200 /*
2201 * Mask off high 16 bits when bytes written as returned by the
2202 * server is greater than bytes requested by the client. OS/2
2203 * servers are known to set incorrect CountHigh values.
2204 */
2205 if (*nbytes > count)
2206 *nbytes &= 0xFFFF;
Steve French50c2f752007-07-13 00:33:32 +00002207 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002208
Steve French4b8f9302006-02-26 16:41:18 +00002209/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00002210 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002211 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00002212 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002213 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002214
Steve French50c2f752007-07-13 00:33:32 +00002215 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002216 since file handle passed in no longer valid */
2217
2218 return rc;
2219}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002220
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002221int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon,
2222 const __u16 netfid, const __u8 lock_type, const __u32 num_unlock,
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002223 const __u32 num_lock, LOCKING_ANDX_RANGE *buf)
2224{
2225 int rc = 0;
2226 LOCK_REQ *pSMB = NULL;
2227 struct kvec iov[2];
2228 int resp_buf_type;
2229 __u16 count;
2230
2231 cFYI(1, "cifs_lockv num lock %d num unlock %d", num_lock, num_unlock);
2232
2233 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2234 if (rc)
2235 return rc;
2236
2237 pSMB->Timeout = 0;
2238 pSMB->NumberOfLocks = cpu_to_le16(num_lock);
2239 pSMB->NumberOfUnlocks = cpu_to_le16(num_unlock);
2240 pSMB->LockType = lock_type;
2241 pSMB->AndXCommand = 0xFF; /* none */
2242 pSMB->Fid = netfid; /* netfid stays le */
2243
2244 count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2245 inc_rfc1001_len(pSMB, count);
2246 pSMB->ByteCount = cpu_to_le16(count);
2247
2248 iov[0].iov_base = (char *)pSMB;
2249 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 -
2250 (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2251 iov[1].iov_base = (char *)buf;
2252 iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2253
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002254 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002255 rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP);
2256 if (rc)
2257 cFYI(1, "Send error in cifs_lockv = %d", rc);
2258
2259 return rc;
2260}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002261
Linus Torvalds1da177e2005-04-16 15:20:36 -07002262int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002263CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002264 const __u16 smb_file_id, const __u32 netpid, const __u64 len,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002265 const __u64 offset, const __u32 numUnlock,
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002266 const __u32 numLock, const __u8 lockType,
2267 const bool waitFlag, const __u8 oplock_level)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002268{
2269 int rc = 0;
2270 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002271/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002272 int bytes_returned;
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002273 int flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002274 __u16 count;
2275
Joe Perchesb6b38f72010-04-21 03:50:45 +00002276 cFYI(1, "CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock);
Steve French46810cb2005-04-28 22:41:09 -07002277 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2278
Linus Torvalds1da177e2005-04-16 15:20:36 -07002279 if (rc)
2280 return rc;
2281
Steve French790fe572007-07-07 19:25:05 +00002282 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002283 /* no response expected */
2284 flags = CIFS_ASYNC_OP | CIFS_OBREAK_OP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002285 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00002286 } else if (waitFlag) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002287 flags = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002288 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
2289 } else {
2290 pSMB->Timeout = 0;
2291 }
2292
2293 pSMB->NumberOfLocks = cpu_to_le16(numLock);
2294 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
2295 pSMB->LockType = lockType;
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002296 pSMB->OplockLevel = oplock_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002297 pSMB->AndXCommand = 0xFF; /* none */
2298 pSMB->Fid = smb_file_id; /* netfid stays le */
2299
Steve French790fe572007-07-07 19:25:05 +00002300 if ((numLock != 0) || (numUnlock != 0)) {
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002301 pSMB->Locks[0].Pid = cpu_to_le16(netpid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002302 /* BB where to store pid high? */
2303 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
2304 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
2305 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
2306 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
2307 count = sizeof(LOCKING_ANDX_RANGE);
2308 } else {
2309 /* oplock break */
2310 count = 0;
2311 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002312 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002313 pSMB->ByteCount = cpu_to_le16(count);
2314
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002315 if (waitFlag) {
2316 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002317 (struct smb_hdr *) pSMB, &bytes_returned);
Steve French133672e2007-11-13 22:41:37 +00002318 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002319 } else {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002320 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, flags);
Steve French133672e2007-11-13 22:41:37 +00002321 /* SMB buffer freed by function above */
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002322 }
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002323 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002324 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002325 cFYI(1, "Send error in Lock = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002326
Steve French50c2f752007-07-13 00:33:32 +00002327 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002328 since file handle passed in no longer valid */
2329 return rc;
2330}
2331
2332int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002333CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002334 const __u16 smb_file_id, const __u32 netpid,
2335 const loff_t start_offset, const __u64 len,
2336 struct file_lock *pLockData, const __u16 lock_type,
2337 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00002338{
2339 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2340 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00002341 struct cifs_posix_lock *parm_data;
2342 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00002343 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00002344 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00002345 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00002346 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00002347 struct kvec iov[1];
Steve French08547b02006-02-28 22:39:25 +00002348
Joe Perchesb6b38f72010-04-21 03:50:45 +00002349 cFYI(1, "Posix Lock");
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002350
Steve French08547b02006-02-28 22:39:25 +00002351 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
2352
2353 if (rc)
2354 return rc;
2355
2356 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
2357
Steve French50c2f752007-07-13 00:33:32 +00002358 params = 6;
Steve French08547b02006-02-28 22:39:25 +00002359 pSMB->MaxSetupCount = 0;
2360 pSMB->Reserved = 0;
2361 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00002362 pSMB->Reserved2 = 0;
2363 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2364 offset = param_offset + params;
2365
Steve French08547b02006-02-28 22:39:25 +00002366 count = sizeof(struct cifs_posix_lock);
2367 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002368 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00002369 pSMB->SetupCount = 1;
2370 pSMB->Reserved3 = 0;
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002371 if (pLockData)
Steve French08547b02006-02-28 22:39:25 +00002372 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2373 else
2374 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2375 byte_count = 3 /* pad */ + params + count;
2376 pSMB->DataCount = cpu_to_le16(count);
2377 pSMB->ParameterCount = cpu_to_le16(params);
2378 pSMB->TotalDataCount = pSMB->DataCount;
2379 pSMB->TotalParameterCount = pSMB->ParameterCount;
2380 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00002381 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00002382 (((char *) &pSMB->hdr.Protocol) + offset);
2383
2384 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00002385 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00002386 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00002387 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00002388 pSMB->Timeout = cpu_to_le32(-1);
2389 } else
2390 pSMB->Timeout = 0;
2391
Pavel Shilovsky4f6bcec2011-10-22 15:33:30 +04002392 parm_data->pid = cpu_to_le32(netpid);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002393 parm_data->start = cpu_to_le64(start_offset);
Steve Frenchcec6815a2006-05-30 18:07:17 +00002394 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00002395
2396 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00002397 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00002398 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
2399 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002400 inc_rfc1001_len(pSMB, byte_count);
Steve French08547b02006-02-28 22:39:25 +00002401 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002402 if (waitFlag) {
2403 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2404 (struct smb_hdr *) pSMBr, &bytes_returned);
2405 } else {
Steve French133672e2007-11-13 22:41:37 +00002406 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002407 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French133672e2007-11-13 22:41:37 +00002408 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
2409 &resp_buf_type, timeout);
2410 pSMB = NULL; /* request buf already freed by SendReceive2. Do
2411 not try to free it twice below on exit */
2412 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002413 }
2414
Steve French08547b02006-02-28 22:39:25 +00002415 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002416 cFYI(1, "Send error in Posix Lock = %d", rc);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002417 } else if (pLockData) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002418 /* lock structure can be returned on get */
2419 __u16 data_offset;
2420 __u16 data_count;
2421 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00002422
Jeff Layton820a8032011-05-04 08:05:26 -04002423 if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002424 rc = -EIO; /* bad smb */
2425 goto plk_err_exit;
2426 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002427 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2428 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00002429 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002430 rc = -EIO;
2431 goto plk_err_exit;
2432 }
2433 parm_data = (struct cifs_posix_lock *)
2434 ((char *)&pSMBr->hdr.Protocol + data_offset);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002435 if (parm_data->lock_type == __constant_cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002436 pLockData->fl_type = F_UNLCK;
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002437 else {
2438 if (parm_data->lock_type ==
2439 __constant_cpu_to_le16(CIFS_RDLCK))
2440 pLockData->fl_type = F_RDLCK;
2441 else if (parm_data->lock_type ==
2442 __constant_cpu_to_le16(CIFS_WRLCK))
2443 pLockData->fl_type = F_WRLCK;
2444
Steve French5443d132011-03-13 05:08:25 +00002445 pLockData->fl_start = le64_to_cpu(parm_data->start);
2446 pLockData->fl_end = pLockData->fl_start +
2447 le64_to_cpu(parm_data->length) - 1;
2448 pLockData->fl_pid = le32_to_cpu(parm_data->pid);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002449 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002450 }
Steve French50c2f752007-07-13 00:33:32 +00002451
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002452plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00002453 if (pSMB)
2454 cifs_small_buf_release(pSMB);
2455
Steve French133672e2007-11-13 22:41:37 +00002456 if (resp_buf_type == CIFS_SMALL_BUFFER)
2457 cifs_small_buf_release(iov[0].iov_base);
2458 else if (resp_buf_type == CIFS_LARGE_BUFFER)
2459 cifs_buf_release(iov[0].iov_base);
2460
Steve French08547b02006-02-28 22:39:25 +00002461 /* Note: On -EAGAIN error only caller can retry on handle based calls
2462 since file handle passed in no longer valid */
2463
2464 return rc;
2465}
2466
2467
2468int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002469CIFSSMBClose(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002470{
2471 int rc = 0;
2472 CLOSE_REQ *pSMB = NULL;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002473 cFYI(1, "In CIFSSMBClose");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002474
2475/* do not retry on dead session on close */
2476 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00002477 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002478 return 0;
2479 if (rc)
2480 return rc;
2481
Linus Torvalds1da177e2005-04-16 15:20:36 -07002482 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00002483 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002484 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002485 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002486 cifs_stats_inc(&tcon->stats.cifs_stats.num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002487 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00002488 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002489 /* EINTR is expected when user ctl-c to kill app */
Joe Perchesb6b38f72010-04-21 03:50:45 +00002490 cERROR(1, "Send error in Close = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002491 }
2492 }
2493
Linus Torvalds1da177e2005-04-16 15:20:36 -07002494 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00002495 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002496 rc = 0;
2497
2498 return rc;
2499}
2500
2501int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002502CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Steve Frenchb298f222009-02-21 21:17:43 +00002503{
2504 int rc = 0;
2505 FLUSH_REQ *pSMB = NULL;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002506 cFYI(1, "In CIFSSMBFlush");
Steve Frenchb298f222009-02-21 21:17:43 +00002507
2508 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
2509 if (rc)
2510 return rc;
2511
2512 pSMB->FileID = (__u16) smb_file_id;
2513 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002514 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002515 cifs_stats_inc(&tcon->stats.cifs_stats.num_flushes);
Steve Frenchb298f222009-02-21 21:17:43 +00002516 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002517 cERROR(1, "Send error in Flush = %d", rc);
Steve Frenchb298f222009-02-21 21:17:43 +00002518
2519 return rc;
2520}
2521
2522int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002523CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002524 const char *from_name, const char *to_name,
2525 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002526{
2527 int rc = 0;
2528 RENAME_REQ *pSMB = NULL;
2529 RENAME_RSP *pSMBr = NULL;
2530 int bytes_returned;
2531 int name_len, name_len2;
2532 __u16 count;
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002533 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002534
Joe Perchesb6b38f72010-04-21 03:50:45 +00002535 cFYI(1, "In CIFSSMBRename");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002536renameRetry:
2537 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
2538 (void **) &pSMBr);
2539 if (rc)
2540 return rc;
2541
2542 pSMB->BufferFormat = 0x04;
2543 pSMB->SearchAttributes =
2544 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2545 ATTR_DIRECTORY);
2546
2547 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002548 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2549 from_name, PATH_MAX,
2550 cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002551 name_len++; /* trailing null */
2552 name_len *= 2;
2553 pSMB->OldFileName[name_len] = 0x04; /* pad */
2554 /* protocol requires ASCII signature byte on Unicode string */
2555 pSMB->OldFileName[name_len + 1] = 0x00;
2556 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002557 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002558 to_name, PATH_MAX, cifs_sb->local_nls,
2559 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002560 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2561 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002562 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002563 name_len = strnlen(from_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002564 name_len++; /* trailing null */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002565 strncpy(pSMB->OldFileName, from_name, name_len);
2566 name_len2 = strnlen(to_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002567 name_len2++; /* trailing null */
2568 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002569 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002570 name_len2++; /* trailing null */
2571 name_len2++; /* signature byte */
2572 }
2573
2574 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002575 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002576 pSMB->ByteCount = cpu_to_le16(count);
2577
2578 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2579 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002580 cifs_stats_inc(&tcon->stats.cifs_stats.num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002581 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002582 cFYI(1, "Send error in rename = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002583
Linus Torvalds1da177e2005-04-16 15:20:36 -07002584 cifs_buf_release(pSMB);
2585
2586 if (rc == -EAGAIN)
2587 goto renameRetry;
2588
2589 return rc;
2590}
2591
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002592int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002593 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002594 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002595{
2596 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2597 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002598 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002599 char *data_offset;
2600 char dummy_string[30];
2601 int rc = 0;
2602 int bytes_returned = 0;
2603 int len_of_str;
2604 __u16 params, param_offset, offset, count, byte_count;
2605
Joe Perchesb6b38f72010-04-21 03:50:45 +00002606 cFYI(1, "Rename to File by handle");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002607 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2608 (void **) &pSMBr);
2609 if (rc)
2610 return rc;
2611
2612 params = 6;
2613 pSMB->MaxSetupCount = 0;
2614 pSMB->Reserved = 0;
2615 pSMB->Flags = 0;
2616 pSMB->Timeout = 0;
2617 pSMB->Reserved2 = 0;
2618 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2619 offset = param_offset + params;
2620
2621 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2622 rename_info = (struct set_file_rename *) data_offset;
2623 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002624 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002625 pSMB->SetupCount = 1;
2626 pSMB->Reserved3 = 0;
2627 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2628 byte_count = 3 /* pad */ + params;
2629 pSMB->ParameterCount = cpu_to_le16(params);
2630 pSMB->TotalParameterCount = pSMB->ParameterCount;
2631 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2632 pSMB->DataOffset = cpu_to_le16(offset);
2633 /* construct random name ".cifs_tmp<inodenum><mid>" */
2634 rename_info->overwrite = cpu_to_le32(1);
2635 rename_info->root_fid = 0;
2636 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002637 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002638 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
Steve Frenchacbbb762012-01-18 22:32:33 -06002639 len_of_str =
2640 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002641 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002642 } else {
Steve Frenchacbbb762012-01-18 22:32:33 -06002643 len_of_str =
2644 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002645 target_name, PATH_MAX, nls_codepage,
2646 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002647 }
2648 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002649 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002650 byte_count += count;
2651 pSMB->DataCount = cpu_to_le16(count);
2652 pSMB->TotalDataCount = pSMB->DataCount;
2653 pSMB->Fid = netfid;
2654 pSMB->InformationLevel =
2655 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2656 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002657 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002658 pSMB->ByteCount = cpu_to_le16(byte_count);
2659 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002660 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002661 cifs_stats_inc(&pTcon->stats.cifs_stats.num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002662 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002663 cFYI(1, "Send error in Rename (by file handle) = %d", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07002664
Linus Torvalds1da177e2005-04-16 15:20:36 -07002665 cifs_buf_release(pSMB);
2666
2667 /* Note: On -EAGAIN error only caller can retry on handle based calls
2668 since file handle passed in no longer valid */
2669
2670 return rc;
2671}
2672
2673int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002674CIFSSMBCopy(const unsigned int xid, struct cifs_tcon *tcon,
2675 const char *fromName, const __u16 target_tid, const char *toName,
2676 const int flags, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002677{
2678 int rc = 0;
2679 COPY_REQ *pSMB = NULL;
2680 COPY_RSP *pSMBr = NULL;
2681 int bytes_returned;
2682 int name_len, name_len2;
2683 __u16 count;
2684
Joe Perchesb6b38f72010-04-21 03:50:45 +00002685 cFYI(1, "In CIFSSMBCopy");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002686copyRetry:
2687 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2688 (void **) &pSMBr);
2689 if (rc)
2690 return rc;
2691
2692 pSMB->BufferFormat = 0x04;
2693 pSMB->Tid2 = target_tid;
2694
2695 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2696
2697 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002698 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2699 fromName, PATH_MAX, nls_codepage,
2700 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002701 name_len++; /* trailing null */
2702 name_len *= 2;
2703 pSMB->OldFileName[name_len] = 0x04; /* pad */
2704 /* protocol requires ASCII signature byte on Unicode string */
2705 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002706 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002707 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2708 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002709 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2710 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002711 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002712 name_len = strnlen(fromName, PATH_MAX);
2713 name_len++; /* trailing null */
2714 strncpy(pSMB->OldFileName, fromName, name_len);
2715 name_len2 = strnlen(toName, PATH_MAX);
2716 name_len2++; /* trailing null */
2717 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2718 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2719 name_len2++; /* trailing null */
2720 name_len2++; /* signature byte */
2721 }
2722
2723 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002724 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002725 pSMB->ByteCount = cpu_to_le16(count);
2726
2727 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2728 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2729 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002730 cFYI(1, "Send error in copy = %d with %d files copied",
2731 rc, le16_to_cpu(pSMBr->CopyCount));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002732 }
Steve French0d817bc2008-05-22 02:02:03 +00002733 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002734
2735 if (rc == -EAGAIN)
2736 goto copyRetry;
2737
2738 return rc;
2739}
2740
2741int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002742CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002743 const char *fromName, const char *toName,
2744 const struct nls_table *nls_codepage)
2745{
2746 TRANSACTION2_SPI_REQ *pSMB = NULL;
2747 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2748 char *data_offset;
2749 int name_len;
2750 int name_len_target;
2751 int rc = 0;
2752 int bytes_returned = 0;
2753 __u16 params, param_offset, offset, byte_count;
2754
Joe Perchesb6b38f72010-04-21 03:50:45 +00002755 cFYI(1, "In Symlink Unix style");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002756createSymLinkRetry:
2757 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2758 (void **) &pSMBr);
2759 if (rc)
2760 return rc;
2761
2762 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2763 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06002764 cifs_strtoUTF16((__le16 *) pSMB->FileName, fromName,
2765 /* find define for this maxpathcomponent */
2766 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002767 name_len++; /* trailing null */
2768 name_len *= 2;
2769
Steve French50c2f752007-07-13 00:33:32 +00002770 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002771 name_len = strnlen(fromName, PATH_MAX);
2772 name_len++; /* trailing null */
2773 strncpy(pSMB->FileName, fromName, name_len);
2774 }
2775 params = 6 + name_len;
2776 pSMB->MaxSetupCount = 0;
2777 pSMB->Reserved = 0;
2778 pSMB->Flags = 0;
2779 pSMB->Timeout = 0;
2780 pSMB->Reserved2 = 0;
2781 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002782 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002783 offset = param_offset + params;
2784
2785 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2786 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2787 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06002788 cifs_strtoUTF16((__le16 *) data_offset, toName, PATH_MAX
2789 /* find define for this maxpathcomponent */
2790 , nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002791 name_len_target++; /* trailing null */
2792 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002793 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002794 name_len_target = strnlen(toName, PATH_MAX);
2795 name_len_target++; /* trailing null */
2796 strncpy(data_offset, toName, name_len_target);
2797 }
2798
2799 pSMB->MaxParameterCount = cpu_to_le16(2);
2800 /* BB find exact max on data count below from sess */
2801 pSMB->MaxDataCount = cpu_to_le16(1000);
2802 pSMB->SetupCount = 1;
2803 pSMB->Reserved3 = 0;
2804 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2805 byte_count = 3 /* pad */ + params + name_len_target;
2806 pSMB->DataCount = cpu_to_le16(name_len_target);
2807 pSMB->ParameterCount = cpu_to_le16(params);
2808 pSMB->TotalDataCount = pSMB->DataCount;
2809 pSMB->TotalParameterCount = pSMB->ParameterCount;
2810 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2811 pSMB->DataOffset = cpu_to_le16(offset);
2812 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2813 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002814 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002815 pSMB->ByteCount = cpu_to_le16(byte_count);
2816 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2817 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002818 cifs_stats_inc(&tcon->stats.cifs_stats.num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002819 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002820 cFYI(1, "Send error in SetPathInfo create symlink = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002821
Steve French0d817bc2008-05-22 02:02:03 +00002822 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002823
2824 if (rc == -EAGAIN)
2825 goto createSymLinkRetry;
2826
2827 return rc;
2828}
2829
2830int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002831CIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002833 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002834{
2835 TRANSACTION2_SPI_REQ *pSMB = NULL;
2836 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2837 char *data_offset;
2838 int name_len;
2839 int name_len_target;
2840 int rc = 0;
2841 int bytes_returned = 0;
2842 __u16 params, param_offset, offset, byte_count;
2843
Joe Perchesb6b38f72010-04-21 03:50:45 +00002844 cFYI(1, "In Create Hard link Unix style");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002845createHardLinkRetry:
2846 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2847 (void **) &pSMBr);
2848 if (rc)
2849 return rc;
2850
2851 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002852 name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, toName,
2853 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002854 name_len++; /* trailing null */
2855 name_len *= 2;
2856
Steve French50c2f752007-07-13 00:33:32 +00002857 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002858 name_len = strnlen(toName, PATH_MAX);
2859 name_len++; /* trailing null */
2860 strncpy(pSMB->FileName, toName, name_len);
2861 }
2862 params = 6 + name_len;
2863 pSMB->MaxSetupCount = 0;
2864 pSMB->Reserved = 0;
2865 pSMB->Flags = 0;
2866 pSMB->Timeout = 0;
2867 pSMB->Reserved2 = 0;
2868 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002869 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002870 offset = param_offset + params;
2871
2872 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2873 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2874 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06002875 cifsConvertToUTF16((__le16 *) data_offset, fromName,
2876 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002877 name_len_target++; /* trailing null */
2878 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002879 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002880 name_len_target = strnlen(fromName, PATH_MAX);
2881 name_len_target++; /* trailing null */
2882 strncpy(data_offset, fromName, name_len_target);
2883 }
2884
2885 pSMB->MaxParameterCount = cpu_to_le16(2);
2886 /* BB find exact max on data count below from sess*/
2887 pSMB->MaxDataCount = cpu_to_le16(1000);
2888 pSMB->SetupCount = 1;
2889 pSMB->Reserved3 = 0;
2890 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2891 byte_count = 3 /* pad */ + params + name_len_target;
2892 pSMB->ParameterCount = cpu_to_le16(params);
2893 pSMB->TotalParameterCount = pSMB->ParameterCount;
2894 pSMB->DataCount = cpu_to_le16(name_len_target);
2895 pSMB->TotalDataCount = pSMB->DataCount;
2896 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2897 pSMB->DataOffset = cpu_to_le16(offset);
2898 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2899 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002900 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002901 pSMB->ByteCount = cpu_to_le16(byte_count);
2902 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2903 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002904 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002905 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002906 cFYI(1, "Send error in SetPathInfo (hard link) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002907
2908 cifs_buf_release(pSMB);
2909 if (rc == -EAGAIN)
2910 goto createHardLinkRetry;
2911
2912 return rc;
2913}
2914
2915int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002916CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchd6e906f2012-09-18 16:20:31 -07002917 const char *from_name, const char *to_name,
2918 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002919{
2920 int rc = 0;
2921 NT_RENAME_REQ *pSMB = NULL;
2922 RENAME_RSP *pSMBr = NULL;
2923 int bytes_returned;
2924 int name_len, name_len2;
2925 __u16 count;
Steve Frenchd6e906f2012-09-18 16:20:31 -07002926 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002927
Joe Perchesb6b38f72010-04-21 03:50:45 +00002928 cFYI(1, "In CIFSCreateHardLink");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002929winCreateHardLinkRetry:
2930
2931 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2932 (void **) &pSMBr);
2933 if (rc)
2934 return rc;
2935
2936 pSMB->SearchAttributes =
2937 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2938 ATTR_DIRECTORY);
2939 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2940 pSMB->ClusterCount = 0;
2941
2942 pSMB->BufferFormat = 0x04;
2943
2944 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2945 name_len =
Steve Frenchd6e906f2012-09-18 16:20:31 -07002946 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, from_name,
2947 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002948 name_len++; /* trailing null */
2949 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05002950
2951 /* protocol specifies ASCII buffer format (0x04) for unicode */
2952 pSMB->OldFileName[name_len] = 0x04;
2953 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002954 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002955 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Steve Frenchd6e906f2012-09-18 16:20:31 -07002956 to_name, PATH_MAX, cifs_sb->local_nls,
2957 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002958 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2959 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002960 } else { /* BB improve the check for buffer overruns BB */
Steve Frenchd6e906f2012-09-18 16:20:31 -07002961 name_len = strnlen(from_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002962 name_len++; /* trailing null */
Steve Frenchd6e906f2012-09-18 16:20:31 -07002963 strncpy(pSMB->OldFileName, from_name, name_len);
2964 name_len2 = strnlen(to_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002965 name_len2++; /* trailing null */
2966 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Steve Frenchd6e906f2012-09-18 16:20:31 -07002967 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002968 name_len2++; /* trailing null */
2969 name_len2++; /* signature byte */
2970 }
2971
2972 count = 1 /* string type byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002973 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002974 pSMB->ByteCount = cpu_to_le16(count);
2975
2976 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2977 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002978 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002979 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002980 cFYI(1, "Send error in hard link (NT rename) = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00002981
Linus Torvalds1da177e2005-04-16 15:20:36 -07002982 cifs_buf_release(pSMB);
2983 if (rc == -EAGAIN)
2984 goto winCreateHardLinkRetry;
2985
2986 return rc;
2987}
2988
2989int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002990CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04002991 const unsigned char *searchName, char **symlinkinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002992 const struct nls_table *nls_codepage)
2993{
2994/* SMB_QUERY_FILE_UNIX_LINK */
2995 TRANSACTION2_QPI_REQ *pSMB = NULL;
2996 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2997 int rc = 0;
2998 int bytes_returned;
2999 int name_len;
3000 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04003001 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003002
Joe Perchesb6b38f72010-04-21 03:50:45 +00003003 cFYI(1, "In QPathSymLinkInfo (Unix) for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003004
3005querySymLinkRetry:
3006 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3007 (void **) &pSMBr);
3008 if (rc)
3009 return rc;
3010
3011 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3012 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003013 cifs_strtoUTF16((__le16 *) pSMB->FileName, searchName,
3014 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003015 name_len++; /* trailing null */
3016 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003017 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003018 name_len = strnlen(searchName, PATH_MAX);
3019 name_len++; /* trailing null */
3020 strncpy(pSMB->FileName, searchName, name_len);
3021 }
3022
3023 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3024 pSMB->TotalDataCount = 0;
3025 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04003026 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003027 pSMB->MaxSetupCount = 0;
3028 pSMB->Reserved = 0;
3029 pSMB->Flags = 0;
3030 pSMB->Timeout = 0;
3031 pSMB->Reserved2 = 0;
3032 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003033 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003034 pSMB->DataCount = 0;
3035 pSMB->DataOffset = 0;
3036 pSMB->SetupCount = 1;
3037 pSMB->Reserved3 = 0;
3038 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3039 byte_count = params + 1 /* pad */ ;
3040 pSMB->TotalParameterCount = cpu_to_le16(params);
3041 pSMB->ParameterCount = pSMB->TotalParameterCount;
3042 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
3043 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003044 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003045 pSMB->ByteCount = cpu_to_le16(byte_count);
3046
3047 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3048 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3049 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003050 cFYI(1, "Send error in QuerySymLinkInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003051 } else {
3052 /* decode response */
3053
3054 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003055 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003056 if (rc || get_bcc(&pSMBr->hdr) < 2)
Jeff Layton460b9692009-04-30 07:17:56 -04003057 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003058 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00003059 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04003060 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003061
Jeff Layton460b9692009-04-30 07:17:56 -04003062 data_start = ((char *) &pSMBr->hdr.Protocol) +
3063 le16_to_cpu(pSMBr->t2.DataOffset);
3064
Steve French0e0d2cf2009-05-01 05:27:32 +00003065 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3066 is_unicode = true;
3067 else
3068 is_unicode = false;
3069
Steve French737b7582005-04-28 22:41:06 -07003070 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchacbbb762012-01-18 22:32:33 -06003071 *symlinkinfo = cifs_strndup_from_utf16(data_start,
3072 count, is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04003073 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04003074 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003075 }
3076 }
3077 cifs_buf_release(pSMB);
3078 if (rc == -EAGAIN)
3079 goto querySymLinkRetry;
3080 return rc;
3081}
3082
Steve Frenchc52a9552011-02-24 06:16:22 +00003083#ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL
3084/*
3085 * Recent Windows versions now create symlinks more frequently
3086 * and they use the "reparse point" mechanism below. We can of course
3087 * do symlinks nicely to Samba and other servers which support the
3088 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
3089 * "MF" symlinks optionally, but for recent Windows we really need to
3090 * reenable the code below and fix the cifs_symlink callers to handle this.
3091 * In the interim this code has been moved to its own config option so
3092 * it is not compiled in by default until callers fixed up and more tested.
3093 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003094int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003095CIFSSMBQueryReparseLinkInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003096 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00003097 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003098 const struct nls_table *nls_codepage)
3099{
3100 int rc = 0;
3101 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00003102 struct smb_com_transaction_ioctl_req *pSMB;
3103 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003104
Joe Perchesb6b38f72010-04-21 03:50:45 +00003105 cFYI(1, "In Windows reparse style QueryLink for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003106 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3107 (void **) &pSMBr);
3108 if (rc)
3109 return rc;
3110
3111 pSMB->TotalParameterCount = 0 ;
3112 pSMB->TotalDataCount = 0;
3113 pSMB->MaxParameterCount = cpu_to_le32(2);
3114 /* BB find exact data count max from sess structure BB */
Jeff Laytonc974bef2011-10-11 06:41:32 -04003115 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003116 pSMB->MaxSetupCount = 4;
3117 pSMB->Reserved = 0;
3118 pSMB->ParameterOffset = 0;
3119 pSMB->DataCount = 0;
3120 pSMB->DataOffset = 0;
3121 pSMB->SetupCount = 4;
3122 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
3123 pSMB->ParameterCount = pSMB->TotalParameterCount;
3124 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
3125 pSMB->IsFsctl = 1; /* FSCTL */
3126 pSMB->IsRootFlag = 0;
3127 pSMB->Fid = fid; /* file handle always le */
3128 pSMB->ByteCount = 0;
3129
3130 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3131 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3132 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003133 cFYI(1, "Send error in QueryReparseLinkInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003134 } else { /* decode response */
3135 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
3136 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
Jeff Layton820a8032011-05-04 08:05:26 -04003137 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
3138 /* BB also check enough total bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003139 rc = -EIO; /* bad smb */
Steve Frenchafe48c32009-05-02 05:25:46 +00003140 goto qreparse_out;
3141 }
3142 if (data_count && (data_count < 2048)) {
3143 char *end_of_smb = 2 /* sizeof byte count */ +
Jeff Layton820a8032011-05-04 08:05:26 -04003144 get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003145
Steve Frenchafe48c32009-05-02 05:25:46 +00003146 struct reparse_data *reparse_buf =
Steve French50c2f752007-07-13 00:33:32 +00003147 (struct reparse_data *)
3148 ((char *)&pSMBr->hdr.Protocol
3149 + data_offset);
Steve Frenchafe48c32009-05-02 05:25:46 +00003150 if ((char *)reparse_buf >= end_of_smb) {
3151 rc = -EIO;
3152 goto qreparse_out;
3153 }
3154 if ((reparse_buf->LinkNamesBuf +
3155 reparse_buf->TargetNameOffset +
3156 reparse_buf->TargetNameLen) > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003157 cFYI(1, "reparse buf beyond SMB");
Steve Frenchafe48c32009-05-02 05:25:46 +00003158 rc = -EIO;
3159 goto qreparse_out;
3160 }
Steve French50c2f752007-07-13 00:33:32 +00003161
Steve Frenchafe48c32009-05-02 05:25:46 +00003162 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3163 cifs_from_ucs2(symlinkinfo, (__le16 *)
Steve French50c2f752007-07-13 00:33:32 +00003164 (reparse_buf->LinkNamesBuf +
3165 reparse_buf->TargetNameOffset),
Steve Frenchafe48c32009-05-02 05:25:46 +00003166 buflen,
3167 reparse_buf->TargetNameLen,
3168 nls_codepage, 0);
3169 } else { /* ASCII names */
3170 strncpy(symlinkinfo,
3171 reparse_buf->LinkNamesBuf +
3172 reparse_buf->TargetNameOffset,
3173 min_t(const int, buflen,
3174 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003175 }
Steve Frenchafe48c32009-05-02 05:25:46 +00003176 } else {
3177 rc = -EIO;
Joe Perchesb6b38f72010-04-21 03:50:45 +00003178 cFYI(1, "Invalid return data count on "
3179 "get reparse info ioctl");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003180 }
Steve Frenchafe48c32009-05-02 05:25:46 +00003181 symlinkinfo[buflen] = 0; /* just in case so the caller
3182 does not go off the end of the buffer */
Joe Perchesb6b38f72010-04-21 03:50:45 +00003183 cFYI(1, "readlink result - %s", symlinkinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003184 }
Steve French989c7e52009-05-02 05:32:20 +00003185
Linus Torvalds1da177e2005-04-16 15:20:36 -07003186qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07003187 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003188
3189 /* Note: On -EAGAIN error only caller can retry on handle based calls
3190 since file handle passed in no longer valid */
3191
3192 return rc;
3193}
Steve Frenchc52a9552011-02-24 06:16:22 +00003194#endif /* CIFS_SYMLINK_EXPERIMENTAL */ /* BB temporarily unused */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003195
3196#ifdef CONFIG_CIFS_POSIX
3197
3198/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00003199static void cifs_convert_ace(posix_acl_xattr_entry *ace,
3200 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003201{
3202 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08003203 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
3204 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
3205 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesb6b38f72010-04-21 03:50:45 +00003206 /* cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003207
3208 return;
3209}
3210
3211/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00003212static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
3213 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003214{
3215 int size = 0;
3216 int i;
3217 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00003218 struct cifs_posix_ace *pACE;
3219 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
3220 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003221
3222 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
3223 return -EOPNOTSUPP;
3224
Steve French790fe572007-07-07 19:25:05 +00003225 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003226 count = le16_to_cpu(cifs_acl->access_entry_count);
3227 pACE = &cifs_acl->ace_array[0];
3228 size = sizeof(struct cifs_posix_acl);
3229 size += sizeof(struct cifs_posix_ace) * count;
3230 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003231 if (size_of_data_area < size) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003232 cFYI(1, "bad CIFS POSIX ACL size %d vs. %d",
3233 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003234 return -EINVAL;
3235 }
Steve French790fe572007-07-07 19:25:05 +00003236 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003237 count = le16_to_cpu(cifs_acl->access_entry_count);
3238 size = sizeof(struct cifs_posix_acl);
3239 size += sizeof(struct cifs_posix_ace) * count;
3240/* skip past access ACEs to get to default ACEs */
3241 pACE = &cifs_acl->ace_array[count];
3242 count = le16_to_cpu(cifs_acl->default_entry_count);
3243 size += sizeof(struct cifs_posix_ace) * count;
3244 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003245 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003246 return -EINVAL;
3247 } else {
3248 /* illegal type */
3249 return -EINVAL;
3250 }
3251
3252 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00003253 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00003254 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00003255 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003256 return -ERANGE;
3257 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08003258 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00003259 for (i = 0; i < count ; i++) {
3260 cifs_convert_ace(&local_acl->a_entries[i], pACE);
3261 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003262 }
3263 }
3264 return size;
3265}
3266
Steve French50c2f752007-07-13 00:33:32 +00003267static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
3268 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003269{
3270 __u16 rc = 0; /* 0 = ACL converted ok */
3271
Steve Frenchff7feac2005-11-15 16:45:16 -08003272 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
3273 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003274 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00003275 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003276 /* Probably no need to le convert -1 on any arch but can not hurt */
3277 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00003278 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08003279 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesb6b38f72010-04-21 03:50:45 +00003280 /*cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id);*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003281 return rc;
3282}
3283
3284/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00003285static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
3286 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003287{
3288 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00003289 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
3290 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003291 int count;
3292 int i;
3293
Steve French790fe572007-07-07 19:25:05 +00003294 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003295 return 0;
3296
3297 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesb6b38f72010-04-21 03:50:45 +00003298 cFYI(1, "setting acl with %d entries from buf of length %d and "
Steve French63135e02007-07-17 17:34:02 +00003299 "version of %d",
Joe Perchesb6b38f72010-04-21 03:50:45 +00003300 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00003301 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003302 cFYI(1, "unknown POSIX ACL version %d",
3303 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003304 return 0;
3305 }
3306 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00003307 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08003308 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00003309 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08003310 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003311 else {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003312 cFYI(1, "unknown ACL type %d", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003313 return 0;
3314 }
Steve French50c2f752007-07-13 00:33:32 +00003315 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003316 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
3317 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00003318 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003319 /* ACE not converted */
3320 break;
3321 }
3322 }
Steve French790fe572007-07-07 19:25:05 +00003323 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003324 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
3325 rc += sizeof(struct cifs_posix_acl);
3326 /* BB add check to make sure ACL does not overflow SMB */
3327 }
3328 return rc;
3329}
3330
3331int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003332CIFSSMBGetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003333 const unsigned char *searchName,
3334 char *acl_inf, const int buflen, const int acl_type,
3335 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003336{
3337/* SMB_QUERY_POSIX_ACL */
3338 TRANSACTION2_QPI_REQ *pSMB = NULL;
3339 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3340 int rc = 0;
3341 int bytes_returned;
3342 int name_len;
3343 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00003344
Joe Perchesb6b38f72010-04-21 03:50:45 +00003345 cFYI(1, "In GetPosixACL (Unix) for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003346
3347queryAclRetry:
3348 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3349 (void **) &pSMBr);
3350 if (rc)
3351 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003352
Linus Torvalds1da177e2005-04-16 15:20:36 -07003353 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3354 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003355 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3356 searchName, PATH_MAX, nls_codepage,
3357 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003358 name_len++; /* trailing null */
3359 name_len *= 2;
3360 pSMB->FileName[name_len] = 0;
3361 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00003362 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003363 name_len = strnlen(searchName, PATH_MAX);
3364 name_len++; /* trailing null */
3365 strncpy(pSMB->FileName, searchName, name_len);
3366 }
3367
3368 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3369 pSMB->TotalDataCount = 0;
3370 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00003371 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003372 pSMB->MaxDataCount = cpu_to_le16(4000);
3373 pSMB->MaxSetupCount = 0;
3374 pSMB->Reserved = 0;
3375 pSMB->Flags = 0;
3376 pSMB->Timeout = 0;
3377 pSMB->Reserved2 = 0;
3378 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003379 offsetof(struct smb_com_transaction2_qpi_req,
3380 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003381 pSMB->DataCount = 0;
3382 pSMB->DataOffset = 0;
3383 pSMB->SetupCount = 1;
3384 pSMB->Reserved3 = 0;
3385 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3386 byte_count = params + 1 /* pad */ ;
3387 pSMB->TotalParameterCount = cpu_to_le16(params);
3388 pSMB->ParameterCount = pSMB->TotalParameterCount;
3389 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
3390 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003391 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003392 pSMB->ByteCount = cpu_to_le16(byte_count);
3393
3394 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3395 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003396 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003397 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003398 cFYI(1, "Send error in Query POSIX ACL = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003399 } else {
3400 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00003401
Linus Torvalds1da177e2005-04-16 15:20:36 -07003402 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003403 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003404 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003405 rc = -EIO; /* bad smb */
3406 else {
3407 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3408 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3409 rc = cifs_copy_posix_acl(acl_inf,
3410 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00003411 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003412 }
3413 }
3414 cifs_buf_release(pSMB);
3415 if (rc == -EAGAIN)
3416 goto queryAclRetry;
3417 return rc;
3418}
3419
3420int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003421CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003422 const unsigned char *fileName,
3423 const char *local_acl, const int buflen,
3424 const int acl_type,
3425 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003426{
3427 struct smb_com_transaction2_spi_req *pSMB = NULL;
3428 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3429 char *parm_data;
3430 int name_len;
3431 int rc = 0;
3432 int bytes_returned = 0;
3433 __u16 params, byte_count, data_count, param_offset, offset;
3434
Joe Perchesb6b38f72010-04-21 03:50:45 +00003435 cFYI(1, "In SetPosixACL (Unix) for path %s", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003436setAclRetry:
3437 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003438 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003439 if (rc)
3440 return rc;
3441 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3442 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003443 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
3444 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003445 name_len++; /* trailing null */
3446 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003447 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003448 name_len = strnlen(fileName, PATH_MAX);
3449 name_len++; /* trailing null */
3450 strncpy(pSMB->FileName, fileName, name_len);
3451 }
3452 params = 6 + name_len;
3453 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003454 /* BB find max SMB size from sess */
3455 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003456 pSMB->MaxSetupCount = 0;
3457 pSMB->Reserved = 0;
3458 pSMB->Flags = 0;
3459 pSMB->Timeout = 0;
3460 pSMB->Reserved2 = 0;
3461 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003462 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003463 offset = param_offset + params;
3464 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
3465 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3466
3467 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00003468 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003469
Steve French790fe572007-07-07 19:25:05 +00003470 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003471 rc = -EOPNOTSUPP;
3472 goto setACLerrorExit;
3473 }
3474 pSMB->DataOffset = cpu_to_le16(offset);
3475 pSMB->SetupCount = 1;
3476 pSMB->Reserved3 = 0;
3477 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3478 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
3479 byte_count = 3 /* pad */ + params + data_count;
3480 pSMB->DataCount = cpu_to_le16(data_count);
3481 pSMB->TotalDataCount = pSMB->DataCount;
3482 pSMB->ParameterCount = cpu_to_le16(params);
3483 pSMB->TotalParameterCount = pSMB->ParameterCount;
3484 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003485 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003486 pSMB->ByteCount = cpu_to_le16(byte_count);
3487 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003488 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003489 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003490 cFYI(1, "Set POSIX ACL returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003491
3492setACLerrorExit:
3493 cifs_buf_release(pSMB);
3494 if (rc == -EAGAIN)
3495 goto setAclRetry;
3496 return rc;
3497}
3498
Steve Frenchf654bac2005-04-28 22:41:04 -07003499/* BB fix tabs in this function FIXME BB */
3500int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003501CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00003502 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07003503{
Steve French50c2f752007-07-13 00:33:32 +00003504 int rc = 0;
3505 struct smb_t2_qfi_req *pSMB = NULL;
3506 struct smb_t2_qfi_rsp *pSMBr = NULL;
3507 int bytes_returned;
3508 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07003509
Joe Perchesb6b38f72010-04-21 03:50:45 +00003510 cFYI(1, "In GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00003511 if (tcon == NULL)
3512 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07003513
3514GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003515 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3516 (void **) &pSMBr);
3517 if (rc)
3518 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003519
Steve Frenchad7a2922008-02-07 23:25:02 +00003520 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003521 pSMB->t2.TotalDataCount = 0;
3522 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3523 /* BB find exact max data count below from sess structure BB */
3524 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3525 pSMB->t2.MaxSetupCount = 0;
3526 pSMB->t2.Reserved = 0;
3527 pSMB->t2.Flags = 0;
3528 pSMB->t2.Timeout = 0;
3529 pSMB->t2.Reserved2 = 0;
3530 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3531 Fid) - 4);
3532 pSMB->t2.DataCount = 0;
3533 pSMB->t2.DataOffset = 0;
3534 pSMB->t2.SetupCount = 1;
3535 pSMB->t2.Reserved3 = 0;
3536 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3537 byte_count = params + 1 /* pad */ ;
3538 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3539 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3540 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3541 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003542 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003543 inc_rfc1001_len(pSMB, byte_count);
Steve French790fe572007-07-07 19:25:05 +00003544 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003545
Steve French790fe572007-07-07 19:25:05 +00003546 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3547 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3548 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003549 cFYI(1, "error %d in GetExtAttr", rc);
Steve French790fe572007-07-07 19:25:05 +00003550 } else {
3551 /* decode response */
3552 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003553 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003554 if (rc || get_bcc(&pSMBr->hdr) < 2)
Steve French790fe572007-07-07 19:25:05 +00003555 /* If rc should we check for EOPNOSUPP and
3556 disable the srvino flag? or in caller? */
3557 rc = -EIO; /* bad smb */
3558 else {
3559 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3560 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3561 struct file_chattr_info *pfinfo;
3562 /* BB Do we need a cast or hash here ? */
3563 if (count != 16) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003564 cFYI(1, "Illegal size ret in GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00003565 rc = -EIO;
3566 goto GetExtAttrOut;
3567 }
3568 pfinfo = (struct file_chattr_info *)
3569 (data_offset + (char *) &pSMBr->hdr.Protocol);
3570 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003571 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003572 }
3573 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003574GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003575 cifs_buf_release(pSMB);
3576 if (rc == -EAGAIN)
3577 goto GetExtAttrRetry;
3578 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003579}
3580
Steve Frenchf654bac2005-04-28 22:41:04 -07003581#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003582
Jeff Layton79df1ba2010-12-06 12:52:08 -05003583#ifdef CONFIG_CIFS_ACL
3584/*
3585 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3586 * all NT TRANSACTS that we init here have total parm and data under about 400
3587 * bytes (to fit in small cifs buffer size), which is the case so far, it
3588 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3589 * returned setup area) and MaxParameterCount (returned parms size) must be set
3590 * by caller
3591 */
3592static int
3593smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French96daf2b2011-05-27 04:34:02 +00003594 const int parm_len, struct cifs_tcon *tcon,
Jeff Layton79df1ba2010-12-06 12:52:08 -05003595 void **ret_buf)
3596{
3597 int rc;
3598 __u32 temp_offset;
3599 struct smb_com_ntransact_req *pSMB;
3600
3601 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3602 (void **)&pSMB);
3603 if (rc)
3604 return rc;
3605 *ret_buf = (void *)pSMB;
3606 pSMB->Reserved = 0;
3607 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3608 pSMB->TotalDataCount = 0;
Jeff Laytonc974bef2011-10-11 06:41:32 -04003609 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003610 pSMB->ParameterCount = pSMB->TotalParameterCount;
3611 pSMB->DataCount = pSMB->TotalDataCount;
3612 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3613 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3614 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3615 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3616 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3617 pSMB->SubCommand = cpu_to_le16(sub_command);
3618 return 0;
3619}
3620
3621static int
3622validate_ntransact(char *buf, char **ppparm, char **ppdata,
3623 __u32 *pparmlen, __u32 *pdatalen)
3624{
3625 char *end_of_smb;
3626 __u32 data_count, data_offset, parm_count, parm_offset;
3627 struct smb_com_ntransact_rsp *pSMBr;
Jeff Layton820a8032011-05-04 08:05:26 -04003628 u16 bcc;
Jeff Layton79df1ba2010-12-06 12:52:08 -05003629
3630 *pdatalen = 0;
3631 *pparmlen = 0;
3632
3633 if (buf == NULL)
3634 return -EINVAL;
3635
3636 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3637
Jeff Layton820a8032011-05-04 08:05:26 -04003638 bcc = get_bcc(&pSMBr->hdr);
3639 end_of_smb = 2 /* sizeof byte count */ + bcc +
Jeff Layton79df1ba2010-12-06 12:52:08 -05003640 (char *)&pSMBr->ByteCount;
3641
3642 data_offset = le32_to_cpu(pSMBr->DataOffset);
3643 data_count = le32_to_cpu(pSMBr->DataCount);
3644 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3645 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3646
3647 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3648 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3649
3650 /* should we also check that parm and data areas do not overlap? */
3651 if (*ppparm > end_of_smb) {
3652 cFYI(1, "parms start after end of smb");
3653 return -EINVAL;
3654 } else if (parm_count + *ppparm > end_of_smb) {
3655 cFYI(1, "parm end after end of smb");
3656 return -EINVAL;
3657 } else if (*ppdata > end_of_smb) {
3658 cFYI(1, "data starts after end of smb");
3659 return -EINVAL;
3660 } else if (data_count + *ppdata > end_of_smb) {
3661 cFYI(1, "data %p + count %d (%p) past smb end %p start %p",
3662 *ppdata, data_count, (data_count + *ppdata),
3663 end_of_smb, pSMBr);
3664 return -EINVAL;
Jeff Layton820a8032011-05-04 08:05:26 -04003665 } else if (parm_count + data_count > bcc) {
Jeff Layton79df1ba2010-12-06 12:52:08 -05003666 cFYI(1, "parm count and data count larger than SMB");
3667 return -EINVAL;
3668 }
3669 *pdatalen = data_count;
3670 *pparmlen = parm_count;
3671 return 0;
3672}
3673
Steve French0a4b92c2006-01-12 15:44:21 -08003674/* Get Security Descriptor (by handle) from remote server for a file or dir */
3675int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003676CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003677 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003678{
3679 int rc = 0;
3680 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003681 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003682 struct kvec iov[1];
3683
Joe Perchesb6b38f72010-04-21 03:50:45 +00003684 cFYI(1, "GetCifsACL");
Steve French0a4b92c2006-01-12 15:44:21 -08003685
Steve French630f3f0c2007-10-25 21:17:17 +00003686 *pbuflen = 0;
3687 *acl_inf = NULL;
3688
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003689 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003690 8 /* parm len */, tcon, (void **) &pSMB);
3691 if (rc)
3692 return rc;
3693
3694 pSMB->MaxParameterCount = cpu_to_le32(4);
3695 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3696 pSMB->MaxSetupCount = 0;
3697 pSMB->Fid = fid; /* file handle always le */
3698 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3699 CIFS_ACL_DACL);
3700 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003701 inc_rfc1001_len(pSMB, 11);
Steve French0a4b92c2006-01-12 15:44:21 -08003702 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003703 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French0a4b92c2006-01-12 15:44:21 -08003704
Steve Frencha761ac52007-10-18 21:45:27 +00003705 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Jeff Layton77499812011-01-11 07:24:23 -05003706 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003707 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Steve French0a4b92c2006-01-12 15:44:21 -08003708 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003709 cFYI(1, "Send error in QuerySecDesc = %d", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08003710 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003711 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003712 __u32 parm_len;
3713 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003714 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003715 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003716
3717/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003718 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003719 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003720 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003721 goto qsec_out;
3722 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3723
Joe Perchesb6b38f72010-04-21 03:50:45 +00003724 cFYI(1, "smb %p parm %p data %p", pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08003725
3726 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3727 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003728 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003729 goto qsec_out;
3730 }
3731
3732/* BB check that data area is minimum length and as big as acl_len */
3733
Steve Frenchaf6f4612007-10-16 18:40:37 +00003734 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003735 if (acl_len != *pbuflen) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003736 cERROR(1, "acl length %d does not match %d",
3737 acl_len, *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003738 if (*pbuflen > acl_len)
3739 *pbuflen = acl_len;
3740 }
Steve French0a4b92c2006-01-12 15:44:21 -08003741
Steve French630f3f0c2007-10-25 21:17:17 +00003742 /* check if buffer is big enough for the acl
3743 header followed by the smallest SID */
3744 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3745 (*pbuflen >= 64 * 1024)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003746 cERROR(1, "bad acl length %d", *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003747 rc = -EINVAL;
3748 *pbuflen = 0;
3749 } else {
3750 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3751 if (*acl_inf == NULL) {
3752 *pbuflen = 0;
3753 rc = -ENOMEM;
3754 }
3755 memcpy(*acl_inf, pdata, *pbuflen);
3756 }
Steve French0a4b92c2006-01-12 15:44:21 -08003757 }
3758qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003759 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003760 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003761 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003762 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003763/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003764 return rc;
3765}
Steve French97837582007-12-31 07:47:21 +00003766
3767int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003768CIFSSMBSetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003769 struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
Steve French97837582007-12-31 07:47:21 +00003770{
3771 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3772 int rc = 0;
3773 int bytes_returned = 0;
3774 SET_SEC_DESC_REQ *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003775 void *pSMBr;
Steve French97837582007-12-31 07:47:21 +00003776
3777setCifsAclRetry:
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003778 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, &pSMBr);
Steve French97837582007-12-31 07:47:21 +00003779 if (rc)
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003780 return rc;
Steve French97837582007-12-31 07:47:21 +00003781
3782 pSMB->MaxSetupCount = 0;
3783 pSMB->Reserved = 0;
3784
3785 param_count = 8;
3786 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3787 data_count = acllen;
3788 data_offset = param_offset + param_count;
3789 byte_count = 3 /* pad */ + param_count;
3790
3791 pSMB->DataCount = cpu_to_le32(data_count);
3792 pSMB->TotalDataCount = pSMB->DataCount;
3793 pSMB->MaxParameterCount = cpu_to_le32(4);
3794 pSMB->MaxDataCount = cpu_to_le32(16384);
3795 pSMB->ParameterCount = cpu_to_le32(param_count);
3796 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3797 pSMB->TotalParameterCount = pSMB->ParameterCount;
3798 pSMB->DataOffset = cpu_to_le32(data_offset);
3799 pSMB->SetupCount = 0;
3800 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3801 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3802
3803 pSMB->Fid = fid; /* file handle always le */
3804 pSMB->Reserved2 = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003805 pSMB->AclFlags = cpu_to_le32(aclflag);
Steve French97837582007-12-31 07:47:21 +00003806
3807 if (pntsd && acllen) {
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003808 memcpy((char *)pSMBr + offsetof(struct smb_hdr, Protocol) +
3809 data_offset, pntsd, acllen);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003810 inc_rfc1001_len(pSMB, byte_count + data_count);
Steve French97837582007-12-31 07:47:21 +00003811 } else
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003812 inc_rfc1001_len(pSMB, byte_count);
Steve French97837582007-12-31 07:47:21 +00003813
3814 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3815 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3816
Joe Perchesb6b38f72010-04-21 03:50:45 +00003817 cFYI(1, "SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00003818 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003819 cFYI(1, "Set CIFS ACL returned %d", rc);
Steve French97837582007-12-31 07:47:21 +00003820 cifs_buf_release(pSMB);
3821
3822 if (rc == -EAGAIN)
3823 goto setCifsAclRetry;
3824
3825 return (rc);
3826}
3827
Jeff Layton79df1ba2010-12-06 12:52:08 -05003828#endif /* CONFIG_CIFS_ACL */
Steve French0a4b92c2006-01-12 15:44:21 -08003829
Steve French6b8edfe2005-08-23 20:26:03 -07003830/* Legacy Query Path Information call for lookup to old servers such
3831 as Win9x/WinME */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003832int
3833SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon,
3834 const char *search_name, FILE_ALL_INFO *data,
3835 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003836{
Steve Frenchad7a2922008-02-07 23:25:02 +00003837 QUERY_INFORMATION_REQ *pSMB;
3838 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003839 int rc = 0;
3840 int bytes_returned;
3841 int name_len;
3842
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003843 cFYI(1, "In SMBQPath path %s", search_name);
Steve French6b8edfe2005-08-23 20:26:03 -07003844QInfRetry:
3845 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003846 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003847 if (rc)
3848 return rc;
3849
3850 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3851 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003852 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003853 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06003854 remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003855 name_len++; /* trailing null */
3856 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003857 } else {
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003858 name_len = strnlen(search_name, PATH_MAX);
Steve French6b8edfe2005-08-23 20:26:03 -07003859 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003860 strncpy(pSMB->FileName, search_name, name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07003861 }
3862 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003863 name_len++; /* account for buffer type byte */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003864 inc_rfc1001_len(pSMB, (__u16)name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07003865 pSMB->ByteCount = cpu_to_le16(name_len);
3866
3867 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003868 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003869 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003870 cFYI(1, "Send error in QueryInfo = %d", rc);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003871 } else if (data) {
Steve French1bd5bbc2006-09-28 03:35:57 +00003872 struct timespec ts;
3873 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00003874
3875 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003876 /* BB FIXME - add time zone adjustment BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003877 memset(data, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003878 ts.tv_nsec = 0;
3879 ts.tv_sec = time;
3880 /* decode time fields */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003881 data->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
3882 data->LastWriteTime = data->ChangeTime;
3883 data->LastAccessTime = 0;
3884 data->AllocationSize =
Steve French70ca7342005-09-22 16:32:06 -07003885 cpu_to_le64(le32_to_cpu(pSMBr->size));
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003886 data->EndOfFile = data->AllocationSize;
3887 data->Attributes =
Steve French70ca7342005-09-22 16:32:06 -07003888 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003889 } else
3890 rc = -EIO; /* bad buffer passed in */
3891
3892 cifs_buf_release(pSMB);
3893
3894 if (rc == -EAGAIN)
3895 goto QInfRetry;
3896
3897 return rc;
3898}
3899
Jeff Laytonbcd53572010-02-12 07:44:16 -05003900int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003901CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonbcd53572010-02-12 07:44:16 -05003902 u16 netfid, FILE_ALL_INFO *pFindData)
3903{
3904 struct smb_t2_qfi_req *pSMB = NULL;
3905 struct smb_t2_qfi_rsp *pSMBr = NULL;
3906 int rc = 0;
3907 int bytes_returned;
3908 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07003909
Jeff Laytonbcd53572010-02-12 07:44:16 -05003910QFileInfoRetry:
3911 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3912 (void **) &pSMBr);
3913 if (rc)
3914 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07003915
Jeff Laytonbcd53572010-02-12 07:44:16 -05003916 params = 2 /* level */ + 2 /* fid */;
3917 pSMB->t2.TotalDataCount = 0;
3918 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3919 /* BB find exact max data count below from sess structure BB */
3920 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3921 pSMB->t2.MaxSetupCount = 0;
3922 pSMB->t2.Reserved = 0;
3923 pSMB->t2.Flags = 0;
3924 pSMB->t2.Timeout = 0;
3925 pSMB->t2.Reserved2 = 0;
3926 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3927 Fid) - 4);
3928 pSMB->t2.DataCount = 0;
3929 pSMB->t2.DataOffset = 0;
3930 pSMB->t2.SetupCount = 1;
3931 pSMB->t2.Reserved3 = 0;
3932 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3933 byte_count = params + 1 /* pad */ ;
3934 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3935 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3936 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3937 pSMB->Pad = 0;
3938 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003939 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003940
3941 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3942 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3943 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00003944 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003945 } else { /* decode response */
3946 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3947
3948 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3949 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04003950 else if (get_bcc(&pSMBr->hdr) < 40)
Jeff Laytonbcd53572010-02-12 07:44:16 -05003951 rc = -EIO; /* bad smb */
3952 else if (pFindData) {
3953 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3954 memcpy((char *) pFindData,
3955 (char *) &pSMBr->hdr.Protocol +
3956 data_offset, sizeof(FILE_ALL_INFO));
3957 } else
3958 rc = -ENOMEM;
3959 }
3960 cifs_buf_release(pSMB);
3961 if (rc == -EAGAIN)
3962 goto QFileInfoRetry;
3963
3964 return rc;
3965}
Steve French6b8edfe2005-08-23 20:26:03 -07003966
Linus Torvalds1da177e2005-04-16 15:20:36 -07003967int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003968CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003969 const char *search_name, FILE_ALL_INFO *data,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003970 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003971 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003972{
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003973 /* level 263 SMB_QUERY_FILE_ALL_INFO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003974 TRANSACTION2_QPI_REQ *pSMB = NULL;
3975 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3976 int rc = 0;
3977 int bytes_returned;
3978 int name_len;
3979 __u16 params, byte_count;
3980
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003981 /* cFYI(1, "In QPathInfo path %s", search_name); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003982QPathInfoRetry:
3983 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3984 (void **) &pSMBr);
3985 if (rc)
3986 return rc;
3987
3988 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3989 name_len =
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003990 cifsConvertToUTF16((__le16 *) pSMB->FileName, search_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06003991 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003992 name_len++; /* trailing null */
3993 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003994 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003995 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003996 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003997 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003998 }
3999
Steve French50c2f752007-07-13 00:33:32 +00004000 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004001 pSMB->TotalDataCount = 0;
4002 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004003 /* BB find exact max SMB PDU from sess structure BB */
4004 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004005 pSMB->MaxSetupCount = 0;
4006 pSMB->Reserved = 0;
4007 pSMB->Flags = 0;
4008 pSMB->Timeout = 0;
4009 pSMB->Reserved2 = 0;
4010 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004011 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004012 pSMB->DataCount = 0;
4013 pSMB->DataOffset = 0;
4014 pSMB->SetupCount = 1;
4015 pSMB->Reserved3 = 0;
4016 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4017 byte_count = params + 1 /* pad */ ;
4018 pSMB->TotalParameterCount = cpu_to_le16(params);
4019 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00004020 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004021 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
4022 else
4023 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004024 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004025 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004026 pSMB->ByteCount = cpu_to_le16(byte_count);
4027
4028 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4029 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4030 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004031 cFYI(1, "Send error in QPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004032 } else { /* decode response */
4033 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4034
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004035 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4036 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004037 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004038 rc = -EIO; /* bad smb */
Jeff Layton820a8032011-05-04 08:05:26 -04004039 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
Steve French50c2f752007-07-13 00:33:32 +00004040 rc = -EIO; /* 24 or 26 expected but we do not read
4041 last field */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004042 else if (data) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004043 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004044 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00004045
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004046 /*
4047 * On legacy responses we do not read the last field,
4048 * EAsize, fortunately since it varies by subdialect and
4049 * also note it differs on Set vs Get, ie two bytes or 4
4050 * bytes depending but we don't care here.
4051 */
Steve Frenchad7a2922008-02-07 23:25:02 +00004052 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004053 size = sizeof(FILE_INFO_STANDARD);
4054 else
4055 size = sizeof(FILE_ALL_INFO);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004056 memcpy((char *) data, (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004057 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004058 } else
4059 rc = -ENOMEM;
4060 }
4061 cifs_buf_release(pSMB);
4062 if (rc == -EAGAIN)
4063 goto QPathInfoRetry;
4064
4065 return rc;
4066}
4067
4068int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004069CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004070 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
4071{
4072 struct smb_t2_qfi_req *pSMB = NULL;
4073 struct smb_t2_qfi_rsp *pSMBr = NULL;
4074 int rc = 0;
4075 int bytes_returned;
4076 __u16 params, byte_count;
4077
4078UnixQFileInfoRetry:
4079 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4080 (void **) &pSMBr);
4081 if (rc)
4082 return rc;
4083
4084 params = 2 /* level */ + 2 /* fid */;
4085 pSMB->t2.TotalDataCount = 0;
4086 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4087 /* BB find exact max data count below from sess structure BB */
4088 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4089 pSMB->t2.MaxSetupCount = 0;
4090 pSMB->t2.Reserved = 0;
4091 pSMB->t2.Flags = 0;
4092 pSMB->t2.Timeout = 0;
4093 pSMB->t2.Reserved2 = 0;
4094 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4095 Fid) - 4);
4096 pSMB->t2.DataCount = 0;
4097 pSMB->t2.DataOffset = 0;
4098 pSMB->t2.SetupCount = 1;
4099 pSMB->t2.Reserved3 = 0;
4100 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4101 byte_count = params + 1 /* pad */ ;
4102 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4103 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4104 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4105 pSMB->Pad = 0;
4106 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004107 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004108
4109 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4110 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4111 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00004112 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004113 } else { /* decode response */
4114 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4115
Jeff Layton820a8032011-05-04 08:05:26 -04004116 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004117 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response. "
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004118 "Unix Extensions can be disabled on mount "
Steve Frenchf19159d2010-04-21 04:12:10 +00004119 "by specifying the nosfu mount option.");
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 Perchesb6b38f72010-04-21 03:50:45 +00004151 cFYI(1, "In QPathInfo (Unix) the path %s", 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 Perchesb6b38f72010-04-21 03:50:45 +00004198 cFYI(1, "Send error in QPathInfo = %d", 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)) {
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004203 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response. "
Steve French1e71f252007-09-20 15:30:07 +00004204 "Unix Extensions can be disabled on mount "
Joe Perchesb6b38f72010-04-21 03:50:45 +00004205 "by specifying the nosfu mount option.");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004206 rc = -EIO; /* bad smb */
4207 } else {
4208 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4209 memcpy((char *) pFindData,
4210 (char *) &pSMBr->hdr.Protocol +
4211 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00004212 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004213 }
4214 }
4215 cifs_buf_release(pSMB);
4216 if (rc == -EAGAIN)
4217 goto UnixQPathInfoRetry;
4218
4219 return rc;
4220}
4221
Linus Torvalds1da177e2005-04-16 15:20:36 -07004222/* xid, tcon, searchName and codepage are input parms, rest are returned */
4223int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004224CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004225 const char *searchName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004226 const struct nls_table *nls_codepage,
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004227 __u16 *pnetfid, __u16 search_flags,
Steve French50c2f752007-07-13 00:33:32 +00004228 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004229{
4230/* level 257 SMB_ */
4231 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
4232 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004233 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004234 int rc = 0;
4235 int bytes_returned = 0;
4236 int name_len;
4237 __u16 params, byte_count;
4238
Joe Perchesb6b38f72010-04-21 03:50:45 +00004239 cFYI(1, "In FindFirst for %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004240
4241findFirstRetry:
4242 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4243 (void **) &pSMBr);
4244 if (rc)
4245 return rc;
4246
4247 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4248 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004249 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4250 PATH_MAX, nls_codepage, remap);
Steve French737b7582005-04-28 22:41:06 -07004251 /* We can not add the asterik earlier in case
4252 it got remapped to 0xF03A as if it were part of the
4253 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004254 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07004255 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07004256 pSMB->FileName[name_len+1] = 0;
4257 pSMB->FileName[name_len+2] = '*';
4258 pSMB->FileName[name_len+3] = 0;
4259 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004260 pSMB->FileName[name_len] = 0; /* null terminate just in case */
4261 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07004262 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004263 } else { /* BB add check for overrun of SMB buf BB */
4264 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004265/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00004266 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004267 free buffer exit; BB */
4268 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07004269 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07004270 pSMB->FileName[name_len+1] = '*';
4271 pSMB->FileName[name_len+2] = 0;
4272 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004273 }
4274
4275 params = 12 + name_len /* includes null */ ;
4276 pSMB->TotalDataCount = 0; /* no EAs */
4277 pSMB->MaxParameterCount = cpu_to_le16(10);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004278 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004279 pSMB->MaxSetupCount = 0;
4280 pSMB->Reserved = 0;
4281 pSMB->Flags = 0;
4282 pSMB->Timeout = 0;
4283 pSMB->Reserved2 = 0;
4284 byte_count = params + 1 /* pad */ ;
4285 pSMB->TotalParameterCount = cpu_to_le16(params);
4286 pSMB->ParameterCount = pSMB->TotalParameterCount;
4287 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00004288 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
4289 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004290 pSMB->DataCount = 0;
4291 pSMB->DataOffset = 0;
4292 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
4293 pSMB->Reserved3 = 0;
4294 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
4295 pSMB->SearchAttributes =
4296 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
4297 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00004298 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004299 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004300 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4301
4302 /* BB what should we set StorageType to? Does it matter? BB */
4303 pSMB->SearchStorageType = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004304 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004305 pSMB->ByteCount = cpu_to_le16(byte_count);
4306
4307 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4308 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004309 cifs_stats_inc(&tcon->stats.cifs_stats.num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004310
Steve French88274812006-03-09 22:21:45 +00004311 if (rc) {/* BB add logic to retry regular search if Unix search
4312 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004313 /* BB Add code to handle unsupported level rc */
Joe Perchesb6b38f72010-04-21 03:50:45 +00004314 cFYI(1, "Error in FindFirst = %d", rc);
Steve French1982c342005-08-17 12:38:22 -07004315
Steve French88274812006-03-09 22:21:45 +00004316 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004317
4318 /* BB eventually could optimize out free and realloc of buf */
4319 /* for this case */
4320 if (rc == -EAGAIN)
4321 goto findFirstRetry;
4322 } else { /* decode response */
4323 /* BB remember to free buffer if error BB */
4324 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00004325 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004326 unsigned int lnoff;
4327
Linus Torvalds1da177e2005-04-16 15:20:36 -07004328 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004329 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004330 else
Steve French4b18f2a2008-04-29 00:06:05 +00004331 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004332
4333 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004334 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00004335 psrch_inf->srch_entries_start =
4336 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004337 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004338 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
4339 le16_to_cpu(pSMBr->t2.ParameterOffset));
4340
Steve French790fe572007-07-07 19:25:05 +00004341 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004342 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004343 else
Steve French4b18f2a2008-04-29 00:06:05 +00004344 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004345
Steve French50c2f752007-07-13 00:33:32 +00004346 psrch_inf->entries_in_buffer =
4347 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00004348 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004349 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004350 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004351 if (CIFSMaxBufSize < lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004352 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00004353 psrch_inf->last_entry = NULL;
4354 return rc;
4355 }
4356
Steve French0752f152008-10-07 20:03:33 +00004357 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00004358 lnoff;
4359
Linus Torvalds1da177e2005-04-16 15:20:36 -07004360 *pnetfid = parms->SearchHandle;
4361 } else {
4362 cifs_buf_release(pSMB);
4363 }
4364 }
4365
4366 return rc;
4367}
4368
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004369int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
4370 __u16 searchHandle, __u16 search_flags,
4371 struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004372{
4373 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
4374 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004375 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004376 char *response_data;
4377 int rc = 0;
Jeff Layton9438fab2011-08-23 07:21:28 -04004378 int bytes_returned;
4379 unsigned int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004380 __u16 params, byte_count;
4381
Joe Perchesb6b38f72010-04-21 03:50:45 +00004382 cFYI(1, "In FindNext");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004383
Steve French4b18f2a2008-04-29 00:06:05 +00004384 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004385 return -ENOENT;
4386
4387 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4388 (void **) &pSMBr);
4389 if (rc)
4390 return rc;
4391
Steve French50c2f752007-07-13 00:33:32 +00004392 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004393 byte_count = 0;
4394 pSMB->TotalDataCount = 0; /* no EAs */
4395 pSMB->MaxParameterCount = cpu_to_le16(8);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004396 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004397 pSMB->MaxSetupCount = 0;
4398 pSMB->Reserved = 0;
4399 pSMB->Flags = 0;
4400 pSMB->Timeout = 0;
4401 pSMB->Reserved2 = 0;
4402 pSMB->ParameterOffset = cpu_to_le16(
4403 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
4404 pSMB->DataCount = 0;
4405 pSMB->DataOffset = 0;
4406 pSMB->SetupCount = 1;
4407 pSMB->Reserved3 = 0;
4408 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
4409 pSMB->SearchHandle = searchHandle; /* always kept as le */
4410 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00004411 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004412 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4413 pSMB->ResumeKey = psrch_inf->resume_key;
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004414 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004415
4416 name_len = psrch_inf->resume_name_len;
4417 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00004418 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004419 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
4420 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07004421 /* 14 byte parm len above enough for 2 byte null terminator */
4422 pSMB->ResumeFileName[name_len] = 0;
4423 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004424 } else {
4425 rc = -EINVAL;
4426 goto FNext2_err_exit;
4427 }
4428 byte_count = params + 1 /* pad */ ;
4429 pSMB->TotalParameterCount = cpu_to_le16(params);
4430 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004431 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004432 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004433
Linus Torvalds1da177e2005-04-16 15:20:36 -07004434 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4435 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004436 cifs_stats_inc(&tcon->stats.cifs_stats.num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004437 if (rc) {
4438 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00004439 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07004440 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00004441 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004442 } else
Joe Perchesb6b38f72010-04-21 03:50:45 +00004443 cFYI(1, "FindNext returned = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004444 } else { /* decode response */
4445 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00004446
Steve French790fe572007-07-07 19:25:05 +00004447 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004448 unsigned int lnoff;
4449
Linus Torvalds1da177e2005-04-16 15:20:36 -07004450 /* BB fixme add lock for file (srch_info) struct here */
4451 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004452 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004453 else
Steve French4b18f2a2008-04-29 00:06:05 +00004454 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004455 response_data = (char *) &pSMBr->hdr.Protocol +
4456 le16_to_cpu(pSMBr->t2.ParameterOffset);
4457 parms = (T2_FNEXT_RSP_PARMS *)response_data;
4458 response_data = (char *)&pSMBr->hdr.Protocol +
4459 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00004460 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00004461 cifs_small_buf_release(
4462 psrch_inf->ntwrk_buf_start);
4463 else
4464 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004465 psrch_inf->srch_entries_start = response_data;
4466 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004467 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00004468 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004469 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004470 else
Steve French4b18f2a2008-04-29 00:06:05 +00004471 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00004472 psrch_inf->entries_in_buffer =
4473 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004474 psrch_inf->index_of_last_entry +=
4475 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004476 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004477 if (CIFSMaxBufSize < lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004478 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00004479 psrch_inf->last_entry = NULL;
4480 return rc;
4481 } else
4482 psrch_inf->last_entry =
4483 psrch_inf->srch_entries_start + lnoff;
4484
Joe Perchesb6b38f72010-04-21 03:50:45 +00004485/* cFYI(1, "fnxt2 entries in buf %d index_of_last %d",
4486 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004487
4488 /* BB fixme add unlock here */
4489 }
4490
4491 }
4492
4493 /* BB On error, should we leave previous search buf (and count and
4494 last entry fields) intact or free the previous one? */
4495
4496 /* Note: On -EAGAIN error only caller can retry on handle based calls
4497 since file handle passed in no longer valid */
4498FNext2_err_exit:
4499 if (rc != 0)
4500 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004501 return rc;
4502}
4503
4504int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004505CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004506 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004507{
4508 int rc = 0;
4509 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004510
Joe Perchesb6b38f72010-04-21 03:50:45 +00004511 cFYI(1, "In CIFSSMBFindClose");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004512 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
4513
4514 /* no sense returning error if session restarted
4515 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00004516 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004517 return 0;
4518 if (rc)
4519 return rc;
4520
Linus Torvalds1da177e2005-04-16 15:20:36 -07004521 pSMB->FileID = searchHandle;
4522 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04004523 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004524 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00004525 cERROR(1, "Send error in FindClose = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00004526
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004527 cifs_stats_inc(&tcon->stats.cifs_stats.num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004528
4529 /* Since session is dead, search handle closed on server already */
4530 if (rc == -EAGAIN)
4531 rc = 0;
4532
4533 return rc;
4534}
4535
Linus Torvalds1da177e2005-04-16 15:20:36 -07004536int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004537CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004538 const char *search_name, __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00004539 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004540{
4541 int rc = 0;
4542 TRANSACTION2_QPI_REQ *pSMB = NULL;
4543 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4544 int name_len, bytes_returned;
4545 __u16 params, byte_count;
4546
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004547 cFYI(1, "In GetSrvInodeNum for %s", search_name);
Steve French790fe572007-07-07 19:25:05 +00004548 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00004549 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004550
4551GetInodeNumberRetry:
4552 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004553 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004554 if (rc)
4555 return rc;
4556
Linus Torvalds1da177e2005-04-16 15:20:36 -07004557 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4558 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004559 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004560 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004561 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004562 name_len++; /* trailing null */
4563 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004564 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004565 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004566 name_len++; /* trailing null */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004567 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004568 }
4569
4570 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4571 pSMB->TotalDataCount = 0;
4572 pSMB->MaxParameterCount = cpu_to_le16(2);
4573 /* BB find exact max data count below from sess structure BB */
4574 pSMB->MaxDataCount = cpu_to_le16(4000);
4575 pSMB->MaxSetupCount = 0;
4576 pSMB->Reserved = 0;
4577 pSMB->Flags = 0;
4578 pSMB->Timeout = 0;
4579 pSMB->Reserved2 = 0;
4580 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004581 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004582 pSMB->DataCount = 0;
4583 pSMB->DataOffset = 0;
4584 pSMB->SetupCount = 1;
4585 pSMB->Reserved3 = 0;
4586 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4587 byte_count = params + 1 /* pad */ ;
4588 pSMB->TotalParameterCount = cpu_to_le16(params);
4589 pSMB->ParameterCount = pSMB->TotalParameterCount;
4590 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4591 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004592 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004593 pSMB->ByteCount = cpu_to_le16(byte_count);
4594
4595 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4596 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4597 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004598 cFYI(1, "error %d in QueryInternalInfo", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004599 } else {
4600 /* decode response */
4601 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004602 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04004603 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004604 /* If rc should we check for EOPNOSUPP and
4605 disable the srvino flag? or in caller? */
4606 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00004607 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004608 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4609 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00004610 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004611 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00004612 if (count < 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004613 cFYI(1, "Illegal size ret in QryIntrnlInf");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004614 rc = -EIO;
4615 goto GetInodeNumOut;
4616 }
4617 pfinfo = (struct file_internal_info *)
4618 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00004619 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004620 }
4621 }
4622GetInodeNumOut:
4623 cifs_buf_release(pSMB);
4624 if (rc == -EAGAIN)
4625 goto GetInodeNumberRetry;
4626 return rc;
4627}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004628
Igor Mammedovfec45852008-05-16 13:06:30 +04004629/* parses DFS refferal V3 structure
4630 * caller is responsible for freeing target_nodes
4631 * returns:
4632 * on success - 0
4633 * on failure - errno
4634 */
4635static int
Steve Frencha1fe78f2008-05-16 18:48:38 +00004636parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
Igor Mammedovfec45852008-05-16 13:06:30 +04004637 unsigned int *num_of_nodes,
4638 struct dfs_info3_param **target_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004639 const struct nls_table *nls_codepage, int remap,
4640 const char *searchName)
Igor Mammedovfec45852008-05-16 13:06:30 +04004641{
4642 int i, rc = 0;
4643 char *data_end;
4644 bool is_unicode;
4645 struct dfs_referral_level_3 *ref;
4646
Harvey Harrison5ca33c62008-07-23 17:45:58 -07004647 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4648 is_unicode = true;
4649 else
4650 is_unicode = false;
Igor Mammedovfec45852008-05-16 13:06:30 +04004651 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
4652
4653 if (*num_of_nodes < 1) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004654 cERROR(1, "num_referrals: must be at least > 0,"
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004655 "but we get num_referrals = %d", *num_of_nodes);
Igor Mammedovfec45852008-05-16 13:06:30 +04004656 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004657 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004658 }
4659
4660 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
Al Viro1d92cfd2008-06-02 10:59:02 +01004661 if (ref->VersionNumber != cpu_to_le16(3)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004662 cERROR(1, "Referrals of V%d version are not supported,"
4663 "should be V3", le16_to_cpu(ref->VersionNumber));
Igor Mammedovfec45852008-05-16 13:06:30 +04004664 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004665 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004666 }
4667
4668 /* get the upper boundary of the resp buffer */
4669 data_end = (char *)(&(pSMBr->PathConsumed)) +
4670 le16_to_cpu(pSMBr->t2.DataCount);
4671
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004672 cFYI(1, "num_referrals: %d dfs flags: 0x%x ...",
Igor Mammedovfec45852008-05-16 13:06:30 +04004673 *num_of_nodes,
Joe Perchesb6b38f72010-04-21 03:50:45 +00004674 le32_to_cpu(pSMBr->DFSFlags));
Igor Mammedovfec45852008-05-16 13:06:30 +04004675
4676 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
4677 *num_of_nodes, GFP_KERNEL);
4678 if (*target_nodes == NULL) {
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004679 cERROR(1, "Failed to allocate buffer for target_nodes");
Igor Mammedovfec45852008-05-16 13:06:30 +04004680 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004681 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004682 }
4683
Daniel Mack3ad2f3f2010-02-03 08:01:28 +08004684 /* collect necessary data from referrals */
Igor Mammedovfec45852008-05-16 13:06:30 +04004685 for (i = 0; i < *num_of_nodes; i++) {
4686 char *temp;
4687 int max_len;
4688 struct dfs_info3_param *node = (*target_nodes)+i;
4689
Steve French0e0d2cf2009-05-01 05:27:32 +00004690 node->flags = le32_to_cpu(pSMBr->DFSFlags);
Igor Mammedov2c556082008-10-23 13:58:42 +04004691 if (is_unicode) {
Jeff Layton331c3132008-12-17 06:31:53 -05004692 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4693 GFP_KERNEL);
Steve French2920ee22009-08-31 15:27:26 +00004694 if (tmp == NULL) {
4695 rc = -ENOMEM;
4696 goto parse_DFS_referrals_exit;
4697 }
Steve Frenchacbbb762012-01-18 22:32:33 -06004698 cifsConvertToUTF16((__le16 *) tmp, searchName,
4699 PATH_MAX, nls_codepage, remap);
4700 node->path_consumed = cifs_utf16_bytes(tmp,
Jeff Layton69f801f2009-04-30 06:46:32 -04004701 le16_to_cpu(pSMBr->PathConsumed),
Igor Mammedov2c556082008-10-23 13:58:42 +04004702 nls_codepage);
4703 kfree(tmp);
4704 } else
4705 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4706
Igor Mammedovfec45852008-05-16 13:06:30 +04004707 node->server_type = le16_to_cpu(ref->ServerType);
4708 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4709
4710 /* copy DfsPath */
4711 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4712 max_len = data_end - temp;
Steve Frenchacbbb762012-01-18 22:32:33 -06004713 node->path_name = cifs_strndup_from_utf16(temp, max_len,
4714 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004715 if (!node->path_name) {
4716 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004717 goto parse_DFS_referrals_exit;
Jeff Layton066ce682009-04-30 07:16:14 -04004718 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004719
4720 /* copy link target UNC */
4721 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4722 max_len = data_end - temp;
Steve Frenchacbbb762012-01-18 22:32:33 -06004723 node->node_name = cifs_strndup_from_utf16(temp, max_len,
4724 is_unicode, nls_codepage);
Stefan Metzmacherd8f27992012-05-04 00:19:28 +02004725 if (!node->node_name) {
Jeff Laytond8e2f532009-05-14 07:46:59 -04004726 rc = -ENOMEM;
Stefan Metzmacherd8f27992012-05-04 00:19:28 +02004727 goto parse_DFS_referrals_exit;
4728 }
4729
4730 ref++;
Igor Mammedovfec45852008-05-16 13:06:30 +04004731 }
4732
Steve Frencha1fe78f2008-05-16 18:48:38 +00004733parse_DFS_referrals_exit:
Igor Mammedovfec45852008-05-16 13:06:30 +04004734 if (rc) {
4735 free_dfs_info_array(*target_nodes, *num_of_nodes);
4736 *target_nodes = NULL;
4737 *num_of_nodes = 0;
4738 }
4739 return rc;
4740}
4741
Linus Torvalds1da177e2005-04-16 15:20:36 -07004742int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004743CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004744 const char *search_name, struct dfs_info3_param **target_nodes,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004745 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004746 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004747{
4748/* TRANS2_GET_DFS_REFERRAL */
4749 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4750 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004751 int rc = 0;
4752 int bytes_returned;
4753 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004754 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004755 *num_of_nodes = 0;
4756 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004757
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004758 cFYI(1, "In GetDFSRefer the path %s", search_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004759 if (ses == NULL)
4760 return -ENODEV;
4761getDFSRetry:
4762 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4763 (void **) &pSMBr);
4764 if (rc)
4765 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004766
4767 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004768 but should never be null here anyway */
Pavel Shilovsky88257362012-05-23 14:01:59 +04004769 pSMB->hdr.Mid = get_next_mid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004770 pSMB->hdr.Tid = ses->ipc_tid;
4771 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004772 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004773 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004774 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004775 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004776
4777 if (ses->capabilities & CAP_UNICODE) {
4778 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4779 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004780 cifsConvertToUTF16((__le16 *) pSMB->RequestFileName,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004781 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004782 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004783 name_len++; /* trailing null */
4784 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004785 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004786 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004787 name_len++; /* trailing null */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004788 strncpy(pSMB->RequestFileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004789 }
4790
Steve French790fe572007-07-07 19:25:05 +00004791 if (ses->server) {
Steve French96daf2b2011-05-27 04:34:02 +00004792 if (ses->server->sec_mode &
Steve French1a4e15a2006-10-12 21:33:51 +00004793 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4794 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4795 }
4796
Steve French50c2f752007-07-13 00:33:32 +00004797 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004798
Linus Torvalds1da177e2005-04-16 15:20:36 -07004799 params = 2 /* level */ + name_len /*includes null */ ;
4800 pSMB->TotalDataCount = 0;
4801 pSMB->DataCount = 0;
4802 pSMB->DataOffset = 0;
4803 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004804 /* BB find exact max SMB PDU from sess structure BB */
4805 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004806 pSMB->MaxSetupCount = 0;
4807 pSMB->Reserved = 0;
4808 pSMB->Flags = 0;
4809 pSMB->Timeout = 0;
4810 pSMB->Reserved2 = 0;
4811 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004812 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004813 pSMB->SetupCount = 1;
4814 pSMB->Reserved3 = 0;
4815 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4816 byte_count = params + 3 /* pad */ ;
4817 pSMB->ParameterCount = cpu_to_le16(params);
4818 pSMB->TotalParameterCount = pSMB->ParameterCount;
4819 pSMB->MaxReferralLevel = cpu_to_le16(3);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004820 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004821 pSMB->ByteCount = cpu_to_le16(byte_count);
4822
4823 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4824 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4825 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004826 cFYI(1, "Send error in GetDFSRefer = %d", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004827 goto GetDFSRefExit;
4828 }
4829 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004830
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004831 /* BB Also check if enough total bytes returned? */
Jeff Layton820a8032011-05-04 08:05:26 -04004832 if (rc || get_bcc(&pSMBr->hdr) < 17) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004833 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004834 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004835 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004836
Joe Perchesb6b38f72010-04-21 03:50:45 +00004837 cFYI(1, "Decoding GetDFSRefer response BCC: %d Offset %d",
Jeff Layton820a8032011-05-04 08:05:26 -04004838 get_bcc(&pSMBr->hdr),
Joe Perchesb6b38f72010-04-21 03:50:45 +00004839 le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04004840
4841 /* parse returned result into more usable form */
Steve Frencha1fe78f2008-05-16 18:48:38 +00004842 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004843 target_nodes, nls_codepage, remap,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004844 search_name);
Igor Mammedovfec45852008-05-16 13:06:30 +04004845
Linus Torvalds1da177e2005-04-16 15:20:36 -07004846GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004847 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004848
4849 if (rc == -EAGAIN)
4850 goto getDFSRetry;
4851
4852 return rc;
4853}
4854
Steve French20962432005-09-21 22:05:57 -07004855/* Query File System Info such as free space to old servers such as Win 9x */
4856int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004857SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4858 struct kstatfs *FSData)
Steve French20962432005-09-21 22:05:57 -07004859{
4860/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4861 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4862 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4863 FILE_SYSTEM_ALLOC_INFO *response_data;
4864 int rc = 0;
4865 int bytes_returned = 0;
4866 __u16 params, byte_count;
4867
Joe Perchesb6b38f72010-04-21 03:50:45 +00004868 cFYI(1, "OldQFSInfo");
Steve French20962432005-09-21 22:05:57 -07004869oldQFSInfoRetry:
4870 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4871 (void **) &pSMBr);
4872 if (rc)
4873 return rc;
Steve French20962432005-09-21 22:05:57 -07004874
4875 params = 2; /* level */
4876 pSMB->TotalDataCount = 0;
4877 pSMB->MaxParameterCount = cpu_to_le16(2);
4878 pSMB->MaxDataCount = cpu_to_le16(1000);
4879 pSMB->MaxSetupCount = 0;
4880 pSMB->Reserved = 0;
4881 pSMB->Flags = 0;
4882 pSMB->Timeout = 0;
4883 pSMB->Reserved2 = 0;
4884 byte_count = params + 1 /* pad */ ;
4885 pSMB->TotalParameterCount = cpu_to_le16(params);
4886 pSMB->ParameterCount = pSMB->TotalParameterCount;
4887 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4888 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4889 pSMB->DataCount = 0;
4890 pSMB->DataOffset = 0;
4891 pSMB->SetupCount = 1;
4892 pSMB->Reserved3 = 0;
4893 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4894 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004895 inc_rfc1001_len(pSMB, byte_count);
Steve French20962432005-09-21 22:05:57 -07004896 pSMB->ByteCount = cpu_to_le16(byte_count);
4897
4898 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4899 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4900 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004901 cFYI(1, "Send error in QFSInfo = %d", rc);
Steve French20962432005-09-21 22:05:57 -07004902 } else { /* decode response */
4903 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4904
Jeff Layton820a8032011-05-04 08:05:26 -04004905 if (rc || get_bcc(&pSMBr->hdr) < 18)
Steve French20962432005-09-21 22:05:57 -07004906 rc = -EIO; /* bad smb */
4907 else {
4908 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004909 cFYI(1, "qfsinf resp BCC: %d Offset %d",
Jeff Layton820a8032011-05-04 08:05:26 -04004910 get_bcc(&pSMBr->hdr), data_offset);
Steve French20962432005-09-21 22:05:57 -07004911
Steve French50c2f752007-07-13 00:33:32 +00004912 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004913 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4914 FSData->f_bsize =
4915 le16_to_cpu(response_data->BytesPerSector) *
4916 le32_to_cpu(response_data->
4917 SectorsPerAllocationUnit);
4918 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004919 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004920 FSData->f_bfree = FSData->f_bavail =
4921 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004922 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
4923 (unsigned long long)FSData->f_blocks,
4924 (unsigned long long)FSData->f_bfree,
4925 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07004926 }
4927 }
4928 cifs_buf_release(pSMB);
4929
4930 if (rc == -EAGAIN)
4931 goto oldQFSInfoRetry;
4932
4933 return rc;
4934}
4935
Linus Torvalds1da177e2005-04-16 15:20:36 -07004936int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004937CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4938 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004939{
4940/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4941 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4942 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4943 FILE_SYSTEM_INFO *response_data;
4944 int rc = 0;
4945 int bytes_returned = 0;
4946 __u16 params, byte_count;
4947
Joe Perchesb6b38f72010-04-21 03:50:45 +00004948 cFYI(1, "In QFSInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004949QFSInfoRetry:
4950 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4951 (void **) &pSMBr);
4952 if (rc)
4953 return rc;
4954
4955 params = 2; /* level */
4956 pSMB->TotalDataCount = 0;
4957 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004958 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004959 pSMB->MaxSetupCount = 0;
4960 pSMB->Reserved = 0;
4961 pSMB->Flags = 0;
4962 pSMB->Timeout = 0;
4963 pSMB->Reserved2 = 0;
4964 byte_count = params + 1 /* pad */ ;
4965 pSMB->TotalParameterCount = cpu_to_le16(params);
4966 pSMB->ParameterCount = pSMB->TotalParameterCount;
4967 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004968 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004969 pSMB->DataCount = 0;
4970 pSMB->DataOffset = 0;
4971 pSMB->SetupCount = 1;
4972 pSMB->Reserved3 = 0;
4973 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4974 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004975 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004976 pSMB->ByteCount = cpu_to_le16(byte_count);
4977
4978 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4979 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4980 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004981 cFYI(1, "Send error in QFSInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004982 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00004983 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004984
Jeff Layton820a8032011-05-04 08:05:26 -04004985 if (rc || get_bcc(&pSMBr->hdr) < 24)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004986 rc = -EIO; /* bad smb */
4987 else {
4988 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004989
4990 response_data =
4991 (FILE_SYSTEM_INFO
4992 *) (((char *) &pSMBr->hdr.Protocol) +
4993 data_offset);
4994 FSData->f_bsize =
4995 le32_to_cpu(response_data->BytesPerSector) *
4996 le32_to_cpu(response_data->
4997 SectorsPerAllocationUnit);
4998 FSData->f_blocks =
4999 le64_to_cpu(response_data->TotalAllocationUnits);
5000 FSData->f_bfree = FSData->f_bavail =
5001 le64_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesb6b38f72010-04-21 03:50:45 +00005002 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
5003 (unsigned long long)FSData->f_blocks,
5004 (unsigned long long)FSData->f_bfree,
5005 FSData->f_bsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005006 }
5007 }
5008 cifs_buf_release(pSMB);
5009
5010 if (rc == -EAGAIN)
5011 goto QFSInfoRetry;
5012
5013 return rc;
5014}
5015
5016int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005017CIFSSMBQFSAttributeInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005018{
5019/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
5020 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5021 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5022 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
5023 int rc = 0;
5024 int bytes_returned = 0;
5025 __u16 params, byte_count;
5026
Joe Perchesb6b38f72010-04-21 03:50:45 +00005027 cFYI(1, "In QFSAttributeInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005028QFSAttributeRetry:
5029 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5030 (void **) &pSMBr);
5031 if (rc)
5032 return rc;
5033
5034 params = 2; /* level */
5035 pSMB->TotalDataCount = 0;
5036 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005037 /* BB find exact max SMB PDU from sess structure BB */
5038 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005039 pSMB->MaxSetupCount = 0;
5040 pSMB->Reserved = 0;
5041 pSMB->Flags = 0;
5042 pSMB->Timeout = 0;
5043 pSMB->Reserved2 = 0;
5044 byte_count = params + 1 /* pad */ ;
5045 pSMB->TotalParameterCount = cpu_to_le16(params);
5046 pSMB->ParameterCount = pSMB->TotalParameterCount;
5047 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005048 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005049 pSMB->DataCount = 0;
5050 pSMB->DataOffset = 0;
5051 pSMB->SetupCount = 1;
5052 pSMB->Reserved3 = 0;
5053 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5054 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005055 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005056 pSMB->ByteCount = cpu_to_le16(byte_count);
5057
5058 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5059 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5060 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005061 cERROR(1, "Send error in QFSAttributeInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005062 } else { /* decode response */
5063 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5064
Jeff Layton820a8032011-05-04 08:05:26 -04005065 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Steve French50c2f752007-07-13 00:33:32 +00005066 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005067 rc = -EIO; /* bad smb */
5068 } else {
5069 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5070 response_data =
5071 (FILE_SYSTEM_ATTRIBUTE_INFO
5072 *) (((char *) &pSMBr->hdr.Protocol) +
5073 data_offset);
5074 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005075 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005076 }
5077 }
5078 cifs_buf_release(pSMB);
5079
5080 if (rc == -EAGAIN)
5081 goto QFSAttributeRetry;
5082
5083 return rc;
5084}
5085
5086int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005087CIFSSMBQFSDeviceInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005088{
5089/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
5090 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5091 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5092 FILE_SYSTEM_DEVICE_INFO *response_data;
5093 int rc = 0;
5094 int bytes_returned = 0;
5095 __u16 params, byte_count;
5096
Joe Perchesb6b38f72010-04-21 03:50:45 +00005097 cFYI(1, "In QFSDeviceInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005098QFSDeviceRetry:
5099 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5100 (void **) &pSMBr);
5101 if (rc)
5102 return rc;
5103
5104 params = 2; /* level */
5105 pSMB->TotalDataCount = 0;
5106 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005107 /* BB find exact max SMB PDU from sess structure BB */
5108 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005109 pSMB->MaxSetupCount = 0;
5110 pSMB->Reserved = 0;
5111 pSMB->Flags = 0;
5112 pSMB->Timeout = 0;
5113 pSMB->Reserved2 = 0;
5114 byte_count = params + 1 /* pad */ ;
5115 pSMB->TotalParameterCount = cpu_to_le16(params);
5116 pSMB->ParameterCount = pSMB->TotalParameterCount;
5117 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005118 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005119
5120 pSMB->DataCount = 0;
5121 pSMB->DataOffset = 0;
5122 pSMB->SetupCount = 1;
5123 pSMB->Reserved3 = 0;
5124 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5125 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005126 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005127 pSMB->ByteCount = cpu_to_le16(byte_count);
5128
5129 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5130 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5131 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005132 cFYI(1, "Send error in QFSDeviceInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005133 } else { /* decode response */
5134 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5135
Jeff Layton820a8032011-05-04 08:05:26 -04005136 if (rc || get_bcc(&pSMBr->hdr) <
5137 sizeof(FILE_SYSTEM_DEVICE_INFO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005138 rc = -EIO; /* bad smb */
5139 else {
5140 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5141 response_data =
Steve French737b7582005-04-28 22:41:06 -07005142 (FILE_SYSTEM_DEVICE_INFO *)
5143 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07005144 data_offset);
5145 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005146 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005147 }
5148 }
5149 cifs_buf_release(pSMB);
5150
5151 if (rc == -EAGAIN)
5152 goto QFSDeviceRetry;
5153
5154 return rc;
5155}
5156
5157int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005158CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005159{
5160/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
5161 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5162 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5163 FILE_SYSTEM_UNIX_INFO *response_data;
5164 int rc = 0;
5165 int bytes_returned = 0;
5166 __u16 params, byte_count;
5167
Joe Perchesb6b38f72010-04-21 03:50:45 +00005168 cFYI(1, "In QFSUnixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005169QFSUnixRetry:
Jeff Laytonf5695992010-09-29 15:27:08 -04005170 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5171 (void **) &pSMB, (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005172 if (rc)
5173 return rc;
5174
5175 params = 2; /* level */
5176 pSMB->TotalDataCount = 0;
5177 pSMB->DataCount = 0;
5178 pSMB->DataOffset = 0;
5179 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005180 /* BB find exact max SMB PDU from sess structure BB */
5181 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005182 pSMB->MaxSetupCount = 0;
5183 pSMB->Reserved = 0;
5184 pSMB->Flags = 0;
5185 pSMB->Timeout = 0;
5186 pSMB->Reserved2 = 0;
5187 byte_count = params + 1 /* pad */ ;
5188 pSMB->ParameterCount = cpu_to_le16(params);
5189 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005190 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5191 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005192 pSMB->SetupCount = 1;
5193 pSMB->Reserved3 = 0;
5194 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5195 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005196 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005197 pSMB->ByteCount = cpu_to_le16(byte_count);
5198
5199 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5200 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5201 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005202 cERROR(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005203 } else { /* decode response */
5204 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5205
Jeff Layton820a8032011-05-04 08:05:26 -04005206 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005207 rc = -EIO; /* bad smb */
5208 } else {
5209 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5210 response_data =
5211 (FILE_SYSTEM_UNIX_INFO
5212 *) (((char *) &pSMBr->hdr.Protocol) +
5213 data_offset);
5214 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005215 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005216 }
5217 }
5218 cifs_buf_release(pSMB);
5219
5220 if (rc == -EAGAIN)
5221 goto QFSUnixRetry;
5222
5223
5224 return rc;
5225}
5226
Jeremy Allisonac670552005-06-22 17:26:35 -07005227int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005228CIFSSMBSetFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07005229{
5230/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
5231 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
5232 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
5233 int rc = 0;
5234 int bytes_returned = 0;
5235 __u16 params, param_offset, offset, byte_count;
5236
Joe Perchesb6b38f72010-04-21 03:50:45 +00005237 cFYI(1, "In SETFSUnixInfo");
Jeremy Allisonac670552005-06-22 17:26:35 -07005238SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00005239 /* BB switch to small buf init to save memory */
Jeff Laytonf5695992010-09-29 15:27:08 -04005240 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5241 (void **) &pSMB, (void **) &pSMBr);
Jeremy Allisonac670552005-06-22 17:26:35 -07005242 if (rc)
5243 return rc;
5244
5245 params = 4; /* 2 bytes zero followed by info level. */
5246 pSMB->MaxSetupCount = 0;
5247 pSMB->Reserved = 0;
5248 pSMB->Flags = 0;
5249 pSMB->Timeout = 0;
5250 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00005251 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
5252 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07005253 offset = param_offset + params;
5254
5255 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00005256 /* BB find exact max SMB PDU from sess structure BB */
5257 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07005258 pSMB->SetupCount = 1;
5259 pSMB->Reserved3 = 0;
5260 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
5261 byte_count = 1 /* pad */ + params + 12;
5262
5263 pSMB->DataCount = cpu_to_le16(12);
5264 pSMB->ParameterCount = cpu_to_le16(params);
5265 pSMB->TotalDataCount = pSMB->DataCount;
5266 pSMB->TotalParameterCount = pSMB->ParameterCount;
5267 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5268 pSMB->DataOffset = cpu_to_le16(offset);
5269
5270 /* Params. */
5271 pSMB->FileNum = 0;
5272 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
5273
5274 /* Data. */
5275 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
5276 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
5277 pSMB->ClientUnixCap = cpu_to_le64(cap);
5278
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005279 inc_rfc1001_len(pSMB, byte_count);
Jeremy Allisonac670552005-06-22 17:26:35 -07005280 pSMB->ByteCount = cpu_to_le16(byte_count);
5281
5282 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5283 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5284 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005285 cERROR(1, "Send error in SETFSUnixInfo = %d", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07005286 } else { /* decode response */
5287 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00005288 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07005289 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07005290 }
5291 cifs_buf_release(pSMB);
5292
5293 if (rc == -EAGAIN)
5294 goto SETFSUnixRetry;
5295
5296 return rc;
5297}
5298
5299
Linus Torvalds1da177e2005-04-16 15:20:36 -07005300
5301int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005302CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon,
Steve French737b7582005-04-28 22:41:06 -07005303 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005304{
5305/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
5306 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5307 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5308 FILE_SYSTEM_POSIX_INFO *response_data;
5309 int rc = 0;
5310 int bytes_returned = 0;
5311 __u16 params, byte_count;
5312
Joe Perchesb6b38f72010-04-21 03:50:45 +00005313 cFYI(1, "In QFSPosixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005314QFSPosixRetry:
5315 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5316 (void **) &pSMBr);
5317 if (rc)
5318 return rc;
5319
5320 params = 2; /* level */
5321 pSMB->TotalDataCount = 0;
5322 pSMB->DataCount = 0;
5323 pSMB->DataOffset = 0;
5324 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005325 /* BB find exact max SMB PDU from sess structure BB */
5326 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005327 pSMB->MaxSetupCount = 0;
5328 pSMB->Reserved = 0;
5329 pSMB->Flags = 0;
5330 pSMB->Timeout = 0;
5331 pSMB->Reserved2 = 0;
5332 byte_count = params + 1 /* pad */ ;
5333 pSMB->ParameterCount = cpu_to_le16(params);
5334 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005335 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5336 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005337 pSMB->SetupCount = 1;
5338 pSMB->Reserved3 = 0;
5339 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5340 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005341 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005342 pSMB->ByteCount = cpu_to_le16(byte_count);
5343
5344 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5345 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5346 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005347 cFYI(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005348 } else { /* decode response */
5349 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5350
Jeff Layton820a8032011-05-04 08:05:26 -04005351 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005352 rc = -EIO; /* bad smb */
5353 } else {
5354 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5355 response_data =
5356 (FILE_SYSTEM_POSIX_INFO
5357 *) (((char *) &pSMBr->hdr.Protocol) +
5358 data_offset);
5359 FSData->f_bsize =
5360 le32_to_cpu(response_data->BlockSize);
5361 FSData->f_blocks =
5362 le64_to_cpu(response_data->TotalBlocks);
5363 FSData->f_bfree =
5364 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00005365 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005366 FSData->f_bavail = FSData->f_bfree;
5367 } else {
5368 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00005369 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005370 }
Steve French790fe572007-07-07 19:25:05 +00005371 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005372 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00005373 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00005374 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005375 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00005376 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005377 }
5378 }
5379 cifs_buf_release(pSMB);
5380
5381 if (rc == -EAGAIN)
5382 goto QFSPosixRetry;
5383
5384 return rc;
5385}
5386
5387
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005388/*
5389 * We can not use write of zero bytes trick to set file size due to need for
5390 * large file support. Also note that this SetPathInfo is preferred to
5391 * SetFileInfo based method in next routine which is only needed to work around
5392 * a sharing violation bugin Samba which this routine can run into.
5393 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005394int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005395CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005396 const char *file_name, __u64 size, struct cifs_sb_info *cifs_sb,
5397 bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005398{
5399 struct smb_com_transaction2_spi_req *pSMB = NULL;
5400 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5401 struct file_end_of_file_info *parm_data;
5402 int name_len;
5403 int rc = 0;
5404 int bytes_returned = 0;
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005405 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
5406
Linus Torvalds1da177e2005-04-16 15:20:36 -07005407 __u16 params, byte_count, data_count, param_offset, offset;
5408
Joe Perchesb6b38f72010-04-21 03:50:45 +00005409 cFYI(1, "In SetEOF");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005410SetEOFRetry:
5411 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5412 (void **) &pSMBr);
5413 if (rc)
5414 return rc;
5415
5416 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5417 name_len =
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005418 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
5419 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005420 name_len++; /* trailing null */
5421 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005422 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005423 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005424 name_len++; /* trailing null */
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005425 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005426 }
5427 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005428 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005429 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07005430 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005431 pSMB->MaxSetupCount = 0;
5432 pSMB->Reserved = 0;
5433 pSMB->Flags = 0;
5434 pSMB->Timeout = 0;
5435 pSMB->Reserved2 = 0;
5436 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005437 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005438 offset = param_offset + params;
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005439 if (set_allocation) {
Steve French50c2f752007-07-13 00:33:32 +00005440 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5441 pSMB->InformationLevel =
5442 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5443 else
5444 pSMB->InformationLevel =
5445 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5446 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005447 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5448 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005449 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005450 else
5451 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005452 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005453 }
5454
5455 parm_data =
5456 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
5457 offset);
5458 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5459 pSMB->DataOffset = cpu_to_le16(offset);
5460 pSMB->SetupCount = 1;
5461 pSMB->Reserved3 = 0;
5462 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5463 byte_count = 3 /* pad */ + params + data_count;
5464 pSMB->DataCount = cpu_to_le16(data_count);
5465 pSMB->TotalDataCount = pSMB->DataCount;
5466 pSMB->ParameterCount = cpu_to_le16(params);
5467 pSMB->TotalParameterCount = pSMB->ParameterCount;
5468 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005469 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005470 parm_data->FileSize = cpu_to_le64(size);
5471 pSMB->ByteCount = cpu_to_le16(byte_count);
5472 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5473 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005474 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005475 cFYI(1, "SetPathInfo (file size) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005476
5477 cifs_buf_release(pSMB);
5478
5479 if (rc == -EAGAIN)
5480 goto SetEOFRetry;
5481
5482 return rc;
5483}
5484
5485int
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005486CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
5487 struct cifsFileInfo *cfile, __u64 size, bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005488{
5489 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005490 struct file_end_of_file_info *parm_data;
5491 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005492 __u16 params, param_offset, offset, byte_count, count;
5493
Joe Perchesb6b38f72010-04-21 03:50:45 +00005494 cFYI(1, "SetFileSize (via SetFileInfo) %lld",
5495 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07005496 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5497
Linus Torvalds1da177e2005-04-16 15:20:36 -07005498 if (rc)
5499 return rc;
5500
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005501 pSMB->hdr.Pid = cpu_to_le16((__u16)cfile->pid);
5502 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(cfile->pid >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005503
Linus Torvalds1da177e2005-04-16 15:20:36 -07005504 params = 6;
5505 pSMB->MaxSetupCount = 0;
5506 pSMB->Reserved = 0;
5507 pSMB->Flags = 0;
5508 pSMB->Timeout = 0;
5509 pSMB->Reserved2 = 0;
5510 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5511 offset = param_offset + params;
5512
Linus Torvalds1da177e2005-04-16 15:20:36 -07005513 count = sizeof(struct file_end_of_file_info);
5514 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005515 /* BB find exact max SMB PDU from sess structure BB */
5516 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005517 pSMB->SetupCount = 1;
5518 pSMB->Reserved3 = 0;
5519 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5520 byte_count = 3 /* pad */ + params + count;
5521 pSMB->DataCount = cpu_to_le16(count);
5522 pSMB->ParameterCount = cpu_to_le16(params);
5523 pSMB->TotalDataCount = pSMB->DataCount;
5524 pSMB->TotalParameterCount = pSMB->ParameterCount;
5525 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5526 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00005527 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
5528 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005529 pSMB->DataOffset = cpu_to_le16(offset);
5530 parm_data->FileSize = cpu_to_le64(size);
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005531 pSMB->Fid = cfile->fid.netfid;
5532 if (set_allocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005533 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5534 pSMB->InformationLevel =
5535 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5536 else
5537 pSMB->InformationLevel =
5538 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00005539 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005540 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5541 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005542 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005543 else
5544 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005545 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005546 }
5547 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005548 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005549 pSMB->ByteCount = cpu_to_le16(byte_count);
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005550 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005551 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005552 cFYI(1, "Send error in SetFileInfo (SetFileSize) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005553 }
5554
Steve French50c2f752007-07-13 00:33:32 +00005555 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005556 since file handle passed in no longer valid */
5557
5558 return rc;
5559}
5560
Steve French50c2f752007-07-13 00:33:32 +00005561/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07005562 an open handle, rather than by pathname - this is awkward due to
5563 potential access conflicts on the open, but it is unavoidable for these
5564 old servers since the only other choice is to go from 100 nanosecond DCE
5565 time and resort to the original setpathinfo level which takes the ancient
5566 DOS time format with 2 second granularity */
5567int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005568CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005569 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005570{
5571 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005572 char *data_offset;
5573 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005574 __u16 params, param_offset, offset, byte_count, count;
5575
Joe Perchesb6b38f72010-04-21 03:50:45 +00005576 cFYI(1, "Set Times (via SetFileInfo)");
Steve Frenchcd634992005-04-28 22:41:10 -07005577 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5578
Linus Torvalds1da177e2005-04-16 15:20:36 -07005579 if (rc)
5580 return rc;
5581
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005582 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5583 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005584
Linus Torvalds1da177e2005-04-16 15:20:36 -07005585 params = 6;
5586 pSMB->MaxSetupCount = 0;
5587 pSMB->Reserved = 0;
5588 pSMB->Flags = 0;
5589 pSMB->Timeout = 0;
5590 pSMB->Reserved2 = 0;
5591 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5592 offset = param_offset + params;
5593
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005594 data_offset = (char *)pSMB +
5595 offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005596
Steve French26f57362007-08-30 22:09:15 +00005597 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005598 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005599 /* BB find max SMB PDU from sess */
5600 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005601 pSMB->SetupCount = 1;
5602 pSMB->Reserved3 = 0;
5603 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5604 byte_count = 3 /* pad */ + params + count;
5605 pSMB->DataCount = cpu_to_le16(count);
5606 pSMB->ParameterCount = cpu_to_le16(params);
5607 pSMB->TotalDataCount = pSMB->DataCount;
5608 pSMB->TotalParameterCount = pSMB->ParameterCount;
5609 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5610 pSMB->DataOffset = cpu_to_le16(offset);
5611 pSMB->Fid = fid;
5612 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5613 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5614 else
5615 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5616 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005617 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005618 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005619 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005620 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005621 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005622 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005623
Steve French50c2f752007-07-13 00:33:32 +00005624 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005625 since file handle passed in no longer valid */
5626
5627 return rc;
5628}
5629
Jeff Layton6d22f092008-09-23 11:48:35 -04005630int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005631CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6d22f092008-09-23 11:48:35 -04005632 bool delete_file, __u16 fid, __u32 pid_of_opener)
5633{
5634 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5635 char *data_offset;
5636 int rc = 0;
5637 __u16 params, param_offset, offset, byte_count, count;
5638
Joe Perchesb6b38f72010-04-21 03:50:45 +00005639 cFYI(1, "Set File Disposition (via SetFileInfo)");
Jeff Layton6d22f092008-09-23 11:48:35 -04005640 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5641
5642 if (rc)
5643 return rc;
5644
5645 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5646 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5647
5648 params = 6;
5649 pSMB->MaxSetupCount = 0;
5650 pSMB->Reserved = 0;
5651 pSMB->Flags = 0;
5652 pSMB->Timeout = 0;
5653 pSMB->Reserved2 = 0;
5654 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5655 offset = param_offset + params;
5656
5657 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5658
5659 count = 1;
5660 pSMB->MaxParameterCount = cpu_to_le16(2);
5661 /* BB find max SMB PDU from sess */
5662 pSMB->MaxDataCount = cpu_to_le16(1000);
5663 pSMB->SetupCount = 1;
5664 pSMB->Reserved3 = 0;
5665 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5666 byte_count = 3 /* pad */ + params + count;
5667 pSMB->DataCount = cpu_to_le16(count);
5668 pSMB->ParameterCount = cpu_to_le16(params);
5669 pSMB->TotalDataCount = pSMB->DataCount;
5670 pSMB->TotalParameterCount = pSMB->ParameterCount;
5671 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5672 pSMB->DataOffset = cpu_to_le16(offset);
5673 pSMB->Fid = fid;
5674 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5675 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005676 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton6d22f092008-09-23 11:48:35 -04005677 pSMB->ByteCount = cpu_to_le16(byte_count);
5678 *data_offset = delete_file ? 1 : 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005679 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Jeff Layton6d22f092008-09-23 11:48:35 -04005680 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005681 cFYI(1, "Send error in SetFileDisposition = %d", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005682
5683 return rc;
5684}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005685
5686int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005687CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6fc000e2008-08-02 07:26:12 -04005688 const char *fileName, const FILE_BASIC_INFO *data,
5689 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005690{
5691 TRANSACTION2_SPI_REQ *pSMB = NULL;
5692 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5693 int name_len;
5694 int rc = 0;
5695 int bytes_returned = 0;
5696 char *data_offset;
5697 __u16 params, param_offset, offset, byte_count, count;
5698
Joe Perchesb6b38f72010-04-21 03:50:45 +00005699 cFYI(1, "In SetTimes");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005700
5701SetTimesRetry:
5702 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5703 (void **) &pSMBr);
5704 if (rc)
5705 return rc;
5706
5707 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5708 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005709 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5710 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005711 name_len++; /* trailing null */
5712 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005713 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005714 name_len = strnlen(fileName, PATH_MAX);
5715 name_len++; /* trailing null */
5716 strncpy(pSMB->FileName, fileName, name_len);
5717 }
5718
5719 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005720 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005721 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005722 /* BB find max SMB PDU from sess structure BB */
5723 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005724 pSMB->MaxSetupCount = 0;
5725 pSMB->Reserved = 0;
5726 pSMB->Flags = 0;
5727 pSMB->Timeout = 0;
5728 pSMB->Reserved2 = 0;
5729 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005730 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005731 offset = param_offset + params;
5732 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5733 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5734 pSMB->DataOffset = cpu_to_le16(offset);
5735 pSMB->SetupCount = 1;
5736 pSMB->Reserved3 = 0;
5737 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5738 byte_count = 3 /* pad */ + params + count;
5739
5740 pSMB->DataCount = cpu_to_le16(count);
5741 pSMB->ParameterCount = cpu_to_le16(params);
5742 pSMB->TotalDataCount = pSMB->DataCount;
5743 pSMB->TotalParameterCount = pSMB->ParameterCount;
5744 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5745 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5746 else
5747 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5748 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005749 inc_rfc1001_len(pSMB, byte_count);
Steve French26f57362007-08-30 22:09:15 +00005750 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005751 pSMB->ByteCount = cpu_to_le16(byte_count);
5752 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5753 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005754 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005755 cFYI(1, "SetPathInfo (times) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005756
5757 cifs_buf_release(pSMB);
5758
5759 if (rc == -EAGAIN)
5760 goto SetTimesRetry;
5761
5762 return rc;
5763}
5764
5765/* Can not be used to set time stamps yet (due to old DOS time format) */
5766/* Can be used to set attributes */
5767#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5768 handling it anyway and NT4 was what we thought it would be needed for
5769 Do not delete it until we prove whether needed for Win9x though */
5770int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005771CIFSSMBSetAttrLegacy(unsigned int xid, struct cifs_tcon *tcon, char *fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005772 __u16 dos_attrs, const struct nls_table *nls_codepage)
5773{
5774 SETATTR_REQ *pSMB = NULL;
5775 SETATTR_RSP *pSMBr = NULL;
5776 int rc = 0;
5777 int bytes_returned;
5778 int name_len;
5779
Joe Perchesb6b38f72010-04-21 03:50:45 +00005780 cFYI(1, "In SetAttrLegacy");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005781
5782SetAttrLgcyRetry:
5783 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5784 (void **) &pSMBr);
5785 if (rc)
5786 return rc;
5787
5788 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5789 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005790 ConvertToUTF16((__le16 *) pSMB->fileName, fileName,
5791 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005792 name_len++; /* trailing null */
5793 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005794 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005795 name_len = strnlen(fileName, PATH_MAX);
5796 name_len++; /* trailing null */
5797 strncpy(pSMB->fileName, fileName, name_len);
5798 }
5799 pSMB->attr = cpu_to_le16(dos_attrs);
5800 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005801 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005802 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5803 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5804 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005805 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005806 cFYI(1, "Error in LegacySetAttr = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005807
5808 cifs_buf_release(pSMB);
5809
5810 if (rc == -EAGAIN)
5811 goto SetAttrLgcyRetry;
5812
5813 return rc;
5814}
5815#endif /* temporarily unneeded SetAttr legacy function */
5816
Jeff Layton654cf142009-07-09 20:02:49 -04005817static void
5818cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5819 const struct cifs_unix_set_info_args *args)
5820{
5821 u64 mode = args->mode;
5822
5823 /*
5824 * Samba server ignores set of file size to zero due to bugs in some
5825 * older clients, but we should be precise - we use SetFileSize to
5826 * set file size and do not want to truncate file size to zero
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005827 * accidentally as happened on one Samba server beta by putting
Jeff Layton654cf142009-07-09 20:02:49 -04005828 * zero instead of -1 here
5829 */
5830 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5831 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5832 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5833 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5834 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5835 data_offset->Uid = cpu_to_le64(args->uid);
5836 data_offset->Gid = cpu_to_le64(args->gid);
5837 /* better to leave device as zero when it is */
5838 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5839 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5840 data_offset->Permissions = cpu_to_le64(mode);
5841
5842 if (S_ISREG(mode))
5843 data_offset->Type = cpu_to_le32(UNIX_FILE);
5844 else if (S_ISDIR(mode))
5845 data_offset->Type = cpu_to_le32(UNIX_DIR);
5846 else if (S_ISLNK(mode))
5847 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5848 else if (S_ISCHR(mode))
5849 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5850 else if (S_ISBLK(mode))
5851 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5852 else if (S_ISFIFO(mode))
5853 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5854 else if (S_ISSOCK(mode))
5855 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5856}
5857
Linus Torvalds1da177e2005-04-16 15:20:36 -07005858int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005859CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005860 const struct cifs_unix_set_info_args *args,
5861 u16 fid, u32 pid_of_opener)
5862{
5863 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005864 char *data_offset;
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005865 int rc = 0;
5866 u16 params, param_offset, offset, byte_count, count;
5867
Joe Perchesb6b38f72010-04-21 03:50:45 +00005868 cFYI(1, "Set Unix Info (via SetFileInfo)");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005869 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5870
5871 if (rc)
5872 return rc;
5873
5874 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5875 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5876
5877 params = 6;
5878 pSMB->MaxSetupCount = 0;
5879 pSMB->Reserved = 0;
5880 pSMB->Flags = 0;
5881 pSMB->Timeout = 0;
5882 pSMB->Reserved2 = 0;
5883 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5884 offset = param_offset + params;
5885
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005886 data_offset = (char *)pSMB +
5887 offsetof(struct smb_hdr, Protocol) + offset;
5888
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005889 count = sizeof(FILE_UNIX_BASIC_INFO);
5890
5891 pSMB->MaxParameterCount = cpu_to_le16(2);
5892 /* BB find max SMB PDU from sess */
5893 pSMB->MaxDataCount = cpu_to_le16(1000);
5894 pSMB->SetupCount = 1;
5895 pSMB->Reserved3 = 0;
5896 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5897 byte_count = 3 /* pad */ + params + count;
5898 pSMB->DataCount = cpu_to_le16(count);
5899 pSMB->ParameterCount = cpu_to_le16(params);
5900 pSMB->TotalDataCount = pSMB->DataCount;
5901 pSMB->TotalParameterCount = pSMB->ParameterCount;
5902 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5903 pSMB->DataOffset = cpu_to_le16(offset);
5904 pSMB->Fid = fid;
5905 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5906 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005907 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005908 pSMB->ByteCount = cpu_to_le16(byte_count);
5909
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005910 cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005911
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005912 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005913 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005914 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005915
5916 /* Note: On -EAGAIN error only caller can retry on handle based calls
5917 since file handle passed in no longer valid */
5918
5919 return rc;
5920}
5921
5922int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005923CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005924 const char *file_name,
Jeff Layton01ea95e2009-07-09 20:02:49 -04005925 const struct cifs_unix_set_info_args *args,
5926 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005927{
5928 TRANSACTION2_SPI_REQ *pSMB = NULL;
5929 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5930 int name_len;
5931 int rc = 0;
5932 int bytes_returned = 0;
5933 FILE_UNIX_BASIC_INFO *data_offset;
5934 __u16 params, param_offset, offset, count, byte_count;
5935
Joe Perchesb6b38f72010-04-21 03:50:45 +00005936 cFYI(1, "In SetUID/GID/Mode");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005937setPermsRetry:
5938 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5939 (void **) &pSMBr);
5940 if (rc)
5941 return rc;
5942
5943 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5944 name_len =
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005945 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06005946 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005947 name_len++; /* trailing null */
5948 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005949 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005950 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005951 name_len++; /* trailing null */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005952 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005953 }
5954
5955 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005956 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005957 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005958 /* BB find max SMB PDU from sess structure BB */
5959 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005960 pSMB->MaxSetupCount = 0;
5961 pSMB->Reserved = 0;
5962 pSMB->Flags = 0;
5963 pSMB->Timeout = 0;
5964 pSMB->Reserved2 = 0;
5965 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005966 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005967 offset = param_offset + params;
5968 data_offset =
5969 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5970 offset);
5971 memset(data_offset, 0, count);
5972 pSMB->DataOffset = cpu_to_le16(offset);
5973 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5974 pSMB->SetupCount = 1;
5975 pSMB->Reserved3 = 0;
5976 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5977 byte_count = 3 /* pad */ + params + count;
5978 pSMB->ParameterCount = cpu_to_le16(params);
5979 pSMB->DataCount = cpu_to_le16(count);
5980 pSMB->TotalParameterCount = pSMB->ParameterCount;
5981 pSMB->TotalDataCount = pSMB->DataCount;
5982 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5983 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005984 inc_rfc1001_len(pSMB, byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005985
Jeff Layton654cf142009-07-09 20:02:49 -04005986 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005987
5988 pSMB->ByteCount = cpu_to_le16(byte_count);
5989 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5990 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005991 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005992 cFYI(1, "SetPathInfo (perms) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005993
Steve French0d817bc2008-05-22 02:02:03 +00005994 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005995 if (rc == -EAGAIN)
5996 goto setPermsRetry;
5997 return rc;
5998}
5999
Linus Torvalds1da177e2005-04-16 15:20:36 -07006000#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05006001/*
6002 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
6003 * function used by listxattr and getxattr type calls. When ea_name is set,
6004 * it looks for that attribute name and stuffs that value into the EAData
6005 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
6006 * buffer. In both cases, the return value is either the length of the
6007 * resulting data or a negative error code. If EAData is a NULL pointer then
6008 * the data isn't copied to it, but the length is returned.
6009 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006010ssize_t
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006011CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05006012 const unsigned char *searchName, const unsigned char *ea_name,
6013 char *EAData, size_t buf_size,
6014 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006015{
6016 /* BB assumes one setup word */
6017 TRANSACTION2_QPI_REQ *pSMB = NULL;
6018 TRANSACTION2_QPI_RSP *pSMBr = NULL;
6019 int rc = 0;
6020 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05006021 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006022 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00006023 struct fea *temp_fea;
6024 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006025 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006026 __u16 params, byte_count, data_offset;
Jeff Layton5980fc92011-07-28 12:48:26 -04006027 unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006028
Joe Perchesb6b38f72010-04-21 03:50:45 +00006029 cFYI(1, "In Query All EAs path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006030QAllEAsRetry:
6031 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6032 (void **) &pSMBr);
6033 if (rc)
6034 return rc;
6035
6036 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05006037 list_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006038 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
6039 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05006040 list_len++; /* trailing null */
6041 list_len *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006042 } else { /* BB improve the check for buffer overruns BB */
Jeff Layton6e462b92010-02-10 16:18:26 -05006043 list_len = strnlen(searchName, PATH_MAX);
6044 list_len++; /* trailing null */
6045 strncpy(pSMB->FileName, searchName, list_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006046 }
6047
Jeff Layton6e462b92010-02-10 16:18:26 -05006048 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006049 pSMB->TotalDataCount = 0;
6050 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006051 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05006052 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006053 pSMB->MaxSetupCount = 0;
6054 pSMB->Reserved = 0;
6055 pSMB->Flags = 0;
6056 pSMB->Timeout = 0;
6057 pSMB->Reserved2 = 0;
6058 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00006059 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006060 pSMB->DataCount = 0;
6061 pSMB->DataOffset = 0;
6062 pSMB->SetupCount = 1;
6063 pSMB->Reserved3 = 0;
6064 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
6065 byte_count = params + 1 /* pad */ ;
6066 pSMB->TotalParameterCount = cpu_to_le16(params);
6067 pSMB->ParameterCount = pSMB->TotalParameterCount;
6068 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
6069 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006070 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006071 pSMB->ByteCount = cpu_to_le16(byte_count);
6072
6073 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6074 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6075 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006076 cFYI(1, "Send error in QueryAllEAs = %d", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05006077 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006078 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006079
6080
6081 /* BB also check enough total bytes returned */
6082 /* BB we need to improve the validity checking
6083 of these trans2 responses */
6084
6085 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Jeff Layton820a8032011-05-04 08:05:26 -04006086 if (rc || get_bcc(&pSMBr->hdr) < 4) {
Jeff Laytonf0d38682010-02-10 16:18:26 -05006087 rc = -EIO; /* bad smb */
6088 goto QAllEAsOut;
6089 }
6090
6091 /* check that length of list is not more than bcc */
6092 /* check that each entry does not go beyond length
6093 of list */
6094 /* check that each element of each entry does not
6095 go beyond end of list */
6096 /* validate_trans2_offsets() */
6097 /* BB check if start of smb + data_offset > &bcc+ bcc */
6098
6099 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
6100 ea_response_data = (struct fealist *)
6101 (((char *) &pSMBr->hdr.Protocol) + data_offset);
6102
Jeff Layton6e462b92010-02-10 16:18:26 -05006103 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesb6b38f72010-04-21 03:50:45 +00006104 cFYI(1, "ea length %d", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05006105 if (list_len <= 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006106 cFYI(1, "empty EA list returned from server");
Jeff Laytonf0d38682010-02-10 16:18:26 -05006107 goto QAllEAsOut;
6108 }
6109
Jeff Layton0cd126b2010-02-10 16:18:26 -05006110 /* make sure list_len doesn't go past end of SMB */
Jeff Layton690c5222011-01-20 13:36:51 -05006111 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
Jeff Layton0cd126b2010-02-10 16:18:26 -05006112 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006113 cFYI(1, "EA list appears to go beyond SMB");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006114 rc = -EIO;
6115 goto QAllEAsOut;
6116 }
6117
Jeff Laytonf0d38682010-02-10 16:18:26 -05006118 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05006119 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006120 temp_fea = ea_response_data->list;
6121 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05006122 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00006123 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006124 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006125
Jeff Layton6e462b92010-02-10 16:18:26 -05006126 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006127 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006128 /* make sure we can read name_len and value_len */
6129 if (list_len < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006130 cFYI(1, "EA entry goes beyond length of list");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006131 rc = -EIO;
6132 goto QAllEAsOut;
6133 }
6134
6135 name_len = temp_fea->name_len;
6136 value_len = le16_to_cpu(temp_fea->value_len);
6137 list_len -= name_len + 1 + value_len;
6138 if (list_len < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006139 cFYI(1, "EA entry goes beyond length of list");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006140 rc = -EIO;
6141 goto QAllEAsOut;
6142 }
6143
Jeff Layton31c05192010-02-10 16:18:26 -05006144 if (ea_name) {
Jeff Layton91d065c2011-07-26 18:23:47 -04006145 if (ea_name_len == name_len &&
Jeff Laytonac423442011-10-11 06:41:32 -04006146 memcmp(ea_name, temp_ptr, name_len) == 0) {
Jeff Layton31c05192010-02-10 16:18:26 -05006147 temp_ptr += name_len + 1;
6148 rc = value_len;
6149 if (buf_size == 0)
6150 goto QAllEAsOut;
6151 if ((size_t)value_len > buf_size) {
6152 rc = -ERANGE;
6153 goto QAllEAsOut;
6154 }
6155 memcpy(EAData, temp_ptr, value_len);
6156 goto QAllEAsOut;
6157 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006158 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05006159 /* account for prefix user. and trailing null */
6160 rc += (5 + 1 + name_len);
6161 if (rc < (int) buf_size) {
6162 memcpy(EAData, "user.", 5);
6163 EAData += 5;
6164 memcpy(EAData, temp_ptr, name_len);
6165 EAData += name_len;
6166 /* null terminate name */
6167 *EAData = 0;
6168 ++EAData;
6169 } else if (buf_size == 0) {
6170 /* skip copy - calc size only */
6171 } else {
6172 /* stop before overrun buffer */
6173 rc = -ERANGE;
6174 break;
6175 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006176 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05006177 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006178 temp_fea = (struct fea *)temp_ptr;
6179 }
6180
Jeff Layton31c05192010-02-10 16:18:26 -05006181 /* didn't find the named attribute */
6182 if (ea_name)
6183 rc = -ENODATA;
6184
Jeff Laytonf0d38682010-02-10 16:18:26 -05006185QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00006186 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006187 if (rc == -EAGAIN)
6188 goto QAllEAsRetry;
6189
6190 return (ssize_t)rc;
6191}
6192
Linus Torvalds1da177e2005-04-16 15:20:36 -07006193int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006194CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
6195 const char *fileName, const char *ea_name, const void *ea_value,
Steve French50c2f752007-07-13 00:33:32 +00006196 const __u16 ea_value_len, const struct nls_table *nls_codepage,
6197 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006198{
6199 struct smb_com_transaction2_spi_req *pSMB = NULL;
6200 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
6201 struct fealist *parm_data;
6202 int name_len;
6203 int rc = 0;
6204 int bytes_returned = 0;
6205 __u16 params, param_offset, byte_count, offset, count;
6206
Joe Perchesb6b38f72010-04-21 03:50:45 +00006207 cFYI(1, "In SetEA");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006208SetEARetry:
6209 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6210 (void **) &pSMBr);
6211 if (rc)
6212 return rc;
6213
6214 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6215 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006216 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
6217 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006218 name_len++; /* trailing null */
6219 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00006220 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006221 name_len = strnlen(fileName, PATH_MAX);
6222 name_len++; /* trailing null */
6223 strncpy(pSMB->FileName, fileName, name_len);
6224 }
6225
6226 params = 6 + name_len;
6227
6228 /* done calculating parms using name_len of file name,
6229 now use name_len to calculate length of ea name
6230 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00006231 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006232 name_len = 0;
6233 else
Steve French50c2f752007-07-13 00:33:32 +00006234 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006235
Steve Frenchdae5dbd2007-12-30 23:49:57 +00006236 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006237 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006238 /* BB find max SMB PDU from sess */
6239 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006240 pSMB->MaxSetupCount = 0;
6241 pSMB->Reserved = 0;
6242 pSMB->Flags = 0;
6243 pSMB->Timeout = 0;
6244 pSMB->Reserved2 = 0;
6245 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006246 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006247 offset = param_offset + params;
6248 pSMB->InformationLevel =
6249 cpu_to_le16(SMB_SET_FILE_EA);
6250
6251 parm_data =
6252 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
6253 offset);
6254 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6255 pSMB->DataOffset = cpu_to_le16(offset);
6256 pSMB->SetupCount = 1;
6257 pSMB->Reserved3 = 0;
6258 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6259 byte_count = 3 /* pad */ + params + count;
6260 pSMB->DataCount = cpu_to_le16(count);
6261 parm_data->list_len = cpu_to_le32(count);
6262 parm_data->list[0].EA_flags = 0;
6263 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08006264 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006265 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00006266 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00006267 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006268 parm_data->list[0].name[name_len] = 0;
6269 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
6270 /* caller ensures that ea_value_len is less than 64K but
6271 we need to ensure that it fits within the smb */
6272
Steve French50c2f752007-07-13 00:33:32 +00006273 /*BB add length check to see if it would fit in
6274 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00006275 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
6276 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00006277 memcpy(parm_data->list[0].name+name_len+1,
6278 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006279
6280 pSMB->TotalDataCount = pSMB->DataCount;
6281 pSMB->ParameterCount = cpu_to_le16(params);
6282 pSMB->TotalParameterCount = pSMB->ParameterCount;
6283 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006284 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006285 pSMB->ByteCount = cpu_to_le16(byte_count);
6286 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6287 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006288 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00006289 cFYI(1, "SetPathInfo (EA) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006290
6291 cifs_buf_release(pSMB);
6292
6293 if (rc == -EAGAIN)
6294 goto SetEARetry;
6295
6296 return rc;
6297}
Linus Torvalds1da177e2005-04-16 15:20:36 -07006298#endif
Steve French0eff0e22011-02-24 05:39:23 +00006299
6300#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */
6301/*
6302 * Years ago the kernel added a "dnotify" function for Samba server,
6303 * to allow network clients (such as Windows) to display updated
6304 * lists of files in directory listings automatically when
6305 * files are added by one user when another user has the
6306 * same directory open on their desktop. The Linux cifs kernel
6307 * client hooked into the kernel side of this interface for
6308 * the same reason, but ironically when the VFS moved from
6309 * "dnotify" to "inotify" it became harder to plug in Linux
6310 * network file system clients (the most obvious use case
6311 * for notify interfaces is when multiple users can update
6312 * the contents of the same directory - exactly what network
6313 * file systems can do) although the server (Samba) could
6314 * still use it. For the short term we leave the worker
6315 * function ifdeffed out (below) until inotify is fixed
6316 * in the VFS to make it easier to plug in network file
6317 * system clients. If inotify turns out to be permanently
6318 * incompatible for network fs clients, we could instead simply
6319 * expose this config flag by adding a future cifs (and smb2) notify ioctl.
6320 */
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006321int CIFSSMBNotify(const unsigned int xid, struct cifs_tcon *tcon,
Steve French0eff0e22011-02-24 05:39:23 +00006322 const int notify_subdirs, const __u16 netfid,
6323 __u32 filter, struct file *pfile, int multishot,
6324 const struct nls_table *nls_codepage)
6325{
6326 int rc = 0;
6327 struct smb_com_transaction_change_notify_req *pSMB = NULL;
6328 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
6329 struct dir_notify_req *dnotify_req;
6330 int bytes_returned;
6331
6332 cFYI(1, "In CIFSSMBNotify for file handle %d", (int)netfid);
6333 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
6334 (void **) &pSMBr);
6335 if (rc)
6336 return rc;
6337
6338 pSMB->TotalParameterCount = 0 ;
6339 pSMB->TotalDataCount = 0;
6340 pSMB->MaxParameterCount = cpu_to_le32(2);
Jeff Laytonc974bef2011-10-11 06:41:32 -04006341 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Steve French0eff0e22011-02-24 05:39:23 +00006342 pSMB->MaxSetupCount = 4;
6343 pSMB->Reserved = 0;
6344 pSMB->ParameterOffset = 0;
6345 pSMB->DataCount = 0;
6346 pSMB->DataOffset = 0;
6347 pSMB->SetupCount = 4; /* single byte does not need le conversion */
6348 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
6349 pSMB->ParameterCount = pSMB->TotalParameterCount;
6350 if (notify_subdirs)
6351 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
6352 pSMB->Reserved2 = 0;
6353 pSMB->CompletionFilter = cpu_to_le32(filter);
6354 pSMB->Fid = netfid; /* file handle always le */
6355 pSMB->ByteCount = 0;
6356
6357 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6358 (struct smb_hdr *)pSMBr, &bytes_returned,
6359 CIFS_ASYNC_OP);
6360 if (rc) {
6361 cFYI(1, "Error in Notify = %d", rc);
6362 } else {
6363 /* Add file to outstanding requests */
6364 /* BB change to kmem cache alloc */
6365 dnotify_req = kmalloc(
6366 sizeof(struct dir_notify_req),
6367 GFP_KERNEL);
6368 if (dnotify_req) {
6369 dnotify_req->Pid = pSMB->hdr.Pid;
6370 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
6371 dnotify_req->Mid = pSMB->hdr.Mid;
6372 dnotify_req->Tid = pSMB->hdr.Tid;
6373 dnotify_req->Uid = pSMB->hdr.Uid;
6374 dnotify_req->netfid = netfid;
6375 dnotify_req->pfile = pfile;
6376 dnotify_req->filter = filter;
6377 dnotify_req->multishot = multishot;
6378 spin_lock(&GlobalMid_Lock);
6379 list_add_tail(&dnotify_req->lhead,
6380 &GlobalDnotifyReqList);
6381 spin_unlock(&GlobalMid_Lock);
6382 } else
6383 rc = -ENOMEM;
6384 }
6385 cifs_buf_release(pSMB);
6386 return rc;
6387}
6388#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */