blob: 2f86c84468cbd9c7ddaba5f52198b5f9425aae34 [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{
2036 int i, rc = -EACCES;
2037 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 Laytonc28c89f2011-05-19 16:22:56 -04002040 struct kvec *iov = NULL;
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
2057 /* 1 iov per page + 1 for header */
Jeff Laytonfec344e2012-09-18 16:20:35 -07002058 rqst.rq_nvec = wdata->nr_pages + 1;
2059 iov = kzalloc((rqst.rq_nvec) * sizeof(*iov), GFP_NOFS);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002060 if (iov == NULL) {
2061 rc = -ENOMEM;
2062 goto async_writev_out;
2063 }
Jeff Laytonfec344e2012-09-18 16:20:35 -07002064 rqst.rq_iov = iov;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002065
Jeff Laytonfe5f5d22012-03-23 14:40:55 -04002066 smb->hdr.Pid = cpu_to_le16((__u16)wdata->pid);
2067 smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16));
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002068
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002069 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07002070 smb->Fid = wdata->cfile->fid.netfid;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002071 smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
2072 if (wct == 14)
2073 smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
2074 smb->Reserved = 0xFFFFFFFF;
2075 smb->WriteMode = 0;
2076 smb->Remaining = 0;
2077
2078 smb->DataOffset =
2079 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
2080
2081 /* 4 for RFC1001 length + 1 for BCC */
2082 iov[0].iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4 + 1;
2083 iov[0].iov_base = smb;
2084
Jeff Laytone9492872012-03-23 14:40:56 -04002085 /*
2086 * This function should marshal up the page array into the kvec
2087 * array, reserving [0] for the header. It should kmap the pages
2088 * and set the iov_len properly for each one. It may also set
2089 * wdata->bytes too.
2090 */
Jeff Layton3cf003c2012-07-11 09:09:36 -04002091 cifs_kmap_lock();
Jeff Laytone9492872012-03-23 14:40:56 -04002092 wdata->marshal_iov(iov, wdata);
Jeff Layton3cf003c2012-07-11 09:09:36 -04002093 cifs_kmap_unlock();
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002094
2095 cFYI(1, "async write at %llu %u bytes", wdata->offset, wdata->bytes);
2096
2097 smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
2098 smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16);
2099
2100 if (wct == 14) {
2101 inc_rfc1001_len(&smb->hdr, wdata->bytes + 1);
2102 put_bcc(wdata->bytes + 1, &smb->hdr);
2103 } else {
2104 /* wct == 12 */
2105 struct smb_com_writex_req *smbw =
2106 (struct smb_com_writex_req *)smb;
2107 inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
2108 put_bcc(wdata->bytes + 5, &smbw->hdr);
2109 iov[0].iov_len += 4; /* pad bigger by four bytes */
2110 }
2111
2112 kref_get(&wdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07002113 rc = cifs_call_async(tcon->ses->server, &rqst, NULL,
2114 cifs_writev_callback, wdata, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002115
2116 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002117 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002118 else
2119 kref_put(&wdata->refcount, cifs_writedata_release);
2120
2121 /* send is done, unmap pages */
2122 for (i = 0; i < wdata->nr_pages; i++)
2123 kunmap(wdata->pages[i]);
2124
2125async_writev_out:
2126 cifs_small_buf_release(smb);
2127 kfree(iov);
2128 return rc;
2129}
2130
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002131int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002132CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
Pavel Shilovskyba9ad7252012-09-18 16:20:30 -07002133 unsigned int *nbytes, struct kvec *iov, int n_vec)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002134{
2135 int rc = -EACCES;
2136 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08002137 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002138 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08002139 int resp_buf_type = 0;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002140 __u32 pid = io_parms->pid;
2141 __u16 netfid = io_parms->netfid;
2142 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00002143 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002144 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002145
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04002146 *nbytes = 0;
2147
Joe Perchesb6b38f72010-04-21 03:50:45 +00002148 cFYI(1, "write2 at %lld %d bytes", (long long)offset, count);
Steve Frenchff7feac2005-11-15 16:45:16 -08002149
Steve French4c3130e2008-12-09 00:28:16 +00002150 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07002151 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00002152 } else {
Steve French8cc64c62005-10-03 13:49:43 -07002153 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00002154 if ((offset >> 32) > 0) {
2155 /* can not handle big offset for old srv */
2156 return -EIO;
2157 }
2158 }
Steve French8cc64c62005-10-03 13:49:43 -07002159 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002160 if (rc)
2161 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002162
2163 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
2164 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
2165
Linus Torvalds1da177e2005-04-16 15:20:36 -07002166 /* tcon and ses pointer are checked in smb_init */
2167 if (tcon->ses->server == NULL)
2168 return -ECONNABORTED;
2169
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002170 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002171 pSMB->Fid = netfid;
2172 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00002173 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002174 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175 pSMB->Reserved = 0xFFFFFFFF;
2176 pSMB->WriteMode = 0;
2177 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002178
Linus Torvalds1da177e2005-04-16 15:20:36 -07002179 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00002180 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002181
Steve French3e844692005-10-03 13:37:24 -07002182 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
2183 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002184 /* header + 1 byte pad */
2185 smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
Steve French790fe572007-07-07 19:25:05 +00002186 if (wct == 14)
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002187 inc_rfc1001_len(pSMB, count + 1);
Steve French8cc64c62005-10-03 13:49:43 -07002188 else /* wct == 12 */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002189 inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
Steve French790fe572007-07-07 19:25:05 +00002190 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002191 pSMB->ByteCount = cpu_to_le16(count + 1);
2192 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00002193 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07002194 (struct smb_com_writex_req *)pSMB;
2195 pSMBW->ByteCount = cpu_to_le16(count + 5);
2196 }
Steve French3e844692005-10-03 13:37:24 -07002197 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00002198 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08002199 iov[0].iov_len = smb_hdr_len + 4;
2200 else /* wct == 12 pad bigger by four bytes */
2201 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00002202
Steve French3e844692005-10-03 13:37:24 -07002203
Pavel Shilovskyba9ad7252012-09-18 16:20:30 -07002204 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002205 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002206 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002207 cFYI(1, "Send error Write2 = %d", rc);
Steve French790fe572007-07-07 19:25:05 +00002208 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08002209 /* presumably this can not happen, but best to be safe */
2210 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002211 } else {
Steve Frenchad7a2922008-02-07 23:25:02 +00002212 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002213 *nbytes = le16_to_cpu(pSMBr->CountHigh);
2214 *nbytes = (*nbytes) << 16;
2215 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05302216
2217 /*
2218 * Mask off high 16 bits when bytes written as returned by the
2219 * server is greater than bytes requested by the client. OS/2
2220 * servers are known to set incorrect CountHigh values.
2221 */
2222 if (*nbytes > count)
2223 *nbytes &= 0xFFFF;
Steve French50c2f752007-07-13 00:33:32 +00002224 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002225
Steve French4b8f9302006-02-26 16:41:18 +00002226/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00002227 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002228 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00002229 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002230 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002231
Steve French50c2f752007-07-13 00:33:32 +00002232 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002233 since file handle passed in no longer valid */
2234
2235 return rc;
2236}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002237
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002238int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon,
2239 const __u16 netfid, const __u8 lock_type, const __u32 num_unlock,
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002240 const __u32 num_lock, LOCKING_ANDX_RANGE *buf)
2241{
2242 int rc = 0;
2243 LOCK_REQ *pSMB = NULL;
2244 struct kvec iov[2];
2245 int resp_buf_type;
2246 __u16 count;
2247
2248 cFYI(1, "cifs_lockv num lock %d num unlock %d", num_lock, num_unlock);
2249
2250 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2251 if (rc)
2252 return rc;
2253
2254 pSMB->Timeout = 0;
2255 pSMB->NumberOfLocks = cpu_to_le16(num_lock);
2256 pSMB->NumberOfUnlocks = cpu_to_le16(num_unlock);
2257 pSMB->LockType = lock_type;
2258 pSMB->AndXCommand = 0xFF; /* none */
2259 pSMB->Fid = netfid; /* netfid stays le */
2260
2261 count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2262 inc_rfc1001_len(pSMB, count);
2263 pSMB->ByteCount = cpu_to_le16(count);
2264
2265 iov[0].iov_base = (char *)pSMB;
2266 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 -
2267 (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2268 iov[1].iov_base = (char *)buf;
2269 iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2270
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002271 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002272 rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP);
2273 if (rc)
2274 cFYI(1, "Send error in cifs_lockv = %d", rc);
2275
2276 return rc;
2277}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002278
Linus Torvalds1da177e2005-04-16 15:20:36 -07002279int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002280CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002281 const __u16 smb_file_id, const __u32 netpid, const __u64 len,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002282 const __u64 offset, const __u32 numUnlock,
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002283 const __u32 numLock, const __u8 lockType,
2284 const bool waitFlag, const __u8 oplock_level)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002285{
2286 int rc = 0;
2287 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002288/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002289 int bytes_returned;
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002290 int flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002291 __u16 count;
2292
Joe Perchesb6b38f72010-04-21 03:50:45 +00002293 cFYI(1, "CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock);
Steve French46810cb2005-04-28 22:41:09 -07002294 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2295
Linus Torvalds1da177e2005-04-16 15:20:36 -07002296 if (rc)
2297 return rc;
2298
Steve French790fe572007-07-07 19:25:05 +00002299 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002300 /* no response expected */
2301 flags = CIFS_ASYNC_OP | CIFS_OBREAK_OP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002302 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00002303 } else if (waitFlag) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002304 flags = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002305 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
2306 } else {
2307 pSMB->Timeout = 0;
2308 }
2309
2310 pSMB->NumberOfLocks = cpu_to_le16(numLock);
2311 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
2312 pSMB->LockType = lockType;
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002313 pSMB->OplockLevel = oplock_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002314 pSMB->AndXCommand = 0xFF; /* none */
2315 pSMB->Fid = smb_file_id; /* netfid stays le */
2316
Steve French790fe572007-07-07 19:25:05 +00002317 if ((numLock != 0) || (numUnlock != 0)) {
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002318 pSMB->Locks[0].Pid = cpu_to_le16(netpid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002319 /* BB where to store pid high? */
2320 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
2321 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
2322 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
2323 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
2324 count = sizeof(LOCKING_ANDX_RANGE);
2325 } else {
2326 /* oplock break */
2327 count = 0;
2328 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002329 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002330 pSMB->ByteCount = cpu_to_le16(count);
2331
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002332 if (waitFlag) {
2333 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002334 (struct smb_hdr *) pSMB, &bytes_returned);
Steve French133672e2007-11-13 22:41:37 +00002335 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002336 } else {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002337 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, flags);
Steve French133672e2007-11-13 22:41:37 +00002338 /* SMB buffer freed by function above */
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002339 }
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002340 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002341 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002342 cFYI(1, "Send error in Lock = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002343
Steve French50c2f752007-07-13 00:33:32 +00002344 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002345 since file handle passed in no longer valid */
2346 return rc;
2347}
2348
2349int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002350CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002351 const __u16 smb_file_id, const __u32 netpid,
2352 const loff_t start_offset, const __u64 len,
2353 struct file_lock *pLockData, const __u16 lock_type,
2354 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00002355{
2356 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2357 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00002358 struct cifs_posix_lock *parm_data;
2359 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00002360 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00002361 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00002362 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00002363 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00002364 struct kvec iov[1];
Steve French08547b02006-02-28 22:39:25 +00002365
Joe Perchesb6b38f72010-04-21 03:50:45 +00002366 cFYI(1, "Posix Lock");
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002367
Steve French08547b02006-02-28 22:39:25 +00002368 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
2369
2370 if (rc)
2371 return rc;
2372
2373 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
2374
Steve French50c2f752007-07-13 00:33:32 +00002375 params = 6;
Steve French08547b02006-02-28 22:39:25 +00002376 pSMB->MaxSetupCount = 0;
2377 pSMB->Reserved = 0;
2378 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00002379 pSMB->Reserved2 = 0;
2380 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2381 offset = param_offset + params;
2382
Steve French08547b02006-02-28 22:39:25 +00002383 count = sizeof(struct cifs_posix_lock);
2384 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002385 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00002386 pSMB->SetupCount = 1;
2387 pSMB->Reserved3 = 0;
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002388 if (pLockData)
Steve French08547b02006-02-28 22:39:25 +00002389 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2390 else
2391 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2392 byte_count = 3 /* pad */ + params + count;
2393 pSMB->DataCount = cpu_to_le16(count);
2394 pSMB->ParameterCount = cpu_to_le16(params);
2395 pSMB->TotalDataCount = pSMB->DataCount;
2396 pSMB->TotalParameterCount = pSMB->ParameterCount;
2397 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00002398 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00002399 (((char *) &pSMB->hdr.Protocol) + offset);
2400
2401 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00002402 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00002403 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00002404 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00002405 pSMB->Timeout = cpu_to_le32(-1);
2406 } else
2407 pSMB->Timeout = 0;
2408
Pavel Shilovsky4f6bcec2011-10-22 15:33:30 +04002409 parm_data->pid = cpu_to_le32(netpid);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002410 parm_data->start = cpu_to_le64(start_offset);
Steve Frenchcec6815a2006-05-30 18:07:17 +00002411 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00002412
2413 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00002414 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00002415 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
2416 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002417 inc_rfc1001_len(pSMB, byte_count);
Steve French08547b02006-02-28 22:39:25 +00002418 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002419 if (waitFlag) {
2420 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2421 (struct smb_hdr *) pSMBr, &bytes_returned);
2422 } else {
Steve French133672e2007-11-13 22:41:37 +00002423 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002424 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French133672e2007-11-13 22:41:37 +00002425 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
2426 &resp_buf_type, timeout);
2427 pSMB = NULL; /* request buf already freed by SendReceive2. Do
2428 not try to free it twice below on exit */
2429 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002430 }
2431
Steve French08547b02006-02-28 22:39:25 +00002432 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002433 cFYI(1, "Send error in Posix Lock = %d", rc);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002434 } else if (pLockData) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002435 /* lock structure can be returned on get */
2436 __u16 data_offset;
2437 __u16 data_count;
2438 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00002439
Jeff Layton820a8032011-05-04 08:05:26 -04002440 if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002441 rc = -EIO; /* bad smb */
2442 goto plk_err_exit;
2443 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002444 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2445 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00002446 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002447 rc = -EIO;
2448 goto plk_err_exit;
2449 }
2450 parm_data = (struct cifs_posix_lock *)
2451 ((char *)&pSMBr->hdr.Protocol + data_offset);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002452 if (parm_data->lock_type == __constant_cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002453 pLockData->fl_type = F_UNLCK;
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002454 else {
2455 if (parm_data->lock_type ==
2456 __constant_cpu_to_le16(CIFS_RDLCK))
2457 pLockData->fl_type = F_RDLCK;
2458 else if (parm_data->lock_type ==
2459 __constant_cpu_to_le16(CIFS_WRLCK))
2460 pLockData->fl_type = F_WRLCK;
2461
Steve French5443d132011-03-13 05:08:25 +00002462 pLockData->fl_start = le64_to_cpu(parm_data->start);
2463 pLockData->fl_end = pLockData->fl_start +
2464 le64_to_cpu(parm_data->length) - 1;
2465 pLockData->fl_pid = le32_to_cpu(parm_data->pid);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002466 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002467 }
Steve French50c2f752007-07-13 00:33:32 +00002468
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002469plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00002470 if (pSMB)
2471 cifs_small_buf_release(pSMB);
2472
Steve French133672e2007-11-13 22:41:37 +00002473 if (resp_buf_type == CIFS_SMALL_BUFFER)
2474 cifs_small_buf_release(iov[0].iov_base);
2475 else if (resp_buf_type == CIFS_LARGE_BUFFER)
2476 cifs_buf_release(iov[0].iov_base);
2477
Steve French08547b02006-02-28 22:39:25 +00002478 /* Note: On -EAGAIN error only caller can retry on handle based calls
2479 since file handle passed in no longer valid */
2480
2481 return rc;
2482}
2483
2484
2485int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002486CIFSSMBClose(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002487{
2488 int rc = 0;
2489 CLOSE_REQ *pSMB = NULL;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002490 cFYI(1, "In CIFSSMBClose");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002491
2492/* do not retry on dead session on close */
2493 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00002494 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002495 return 0;
2496 if (rc)
2497 return rc;
2498
Linus Torvalds1da177e2005-04-16 15:20:36 -07002499 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00002500 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002501 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002502 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002503 cifs_stats_inc(&tcon->stats.cifs_stats.num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002504 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00002505 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002506 /* EINTR is expected when user ctl-c to kill app */
Joe Perchesb6b38f72010-04-21 03:50:45 +00002507 cERROR(1, "Send error in Close = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002508 }
2509 }
2510
Linus Torvalds1da177e2005-04-16 15:20:36 -07002511 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00002512 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002513 rc = 0;
2514
2515 return rc;
2516}
2517
2518int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002519CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Steve Frenchb298f222009-02-21 21:17:43 +00002520{
2521 int rc = 0;
2522 FLUSH_REQ *pSMB = NULL;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002523 cFYI(1, "In CIFSSMBFlush");
Steve Frenchb298f222009-02-21 21:17:43 +00002524
2525 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
2526 if (rc)
2527 return rc;
2528
2529 pSMB->FileID = (__u16) smb_file_id;
2530 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002531 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002532 cifs_stats_inc(&tcon->stats.cifs_stats.num_flushes);
Steve Frenchb298f222009-02-21 21:17:43 +00002533 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002534 cERROR(1, "Send error in Flush = %d", rc);
Steve Frenchb298f222009-02-21 21:17:43 +00002535
2536 return rc;
2537}
2538
2539int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002540CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002541 const char *from_name, const char *to_name,
2542 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002543{
2544 int rc = 0;
2545 RENAME_REQ *pSMB = NULL;
2546 RENAME_RSP *pSMBr = NULL;
2547 int bytes_returned;
2548 int name_len, name_len2;
2549 __u16 count;
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002550 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002551
Joe Perchesb6b38f72010-04-21 03:50:45 +00002552 cFYI(1, "In CIFSSMBRename");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002553renameRetry:
2554 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
2555 (void **) &pSMBr);
2556 if (rc)
2557 return rc;
2558
2559 pSMB->BufferFormat = 0x04;
2560 pSMB->SearchAttributes =
2561 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2562 ATTR_DIRECTORY);
2563
2564 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002565 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2566 from_name, PATH_MAX,
2567 cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002568 name_len++; /* trailing null */
2569 name_len *= 2;
2570 pSMB->OldFileName[name_len] = 0x04; /* pad */
2571 /* protocol requires ASCII signature byte on Unicode string */
2572 pSMB->OldFileName[name_len + 1] = 0x00;
2573 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002574 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002575 to_name, PATH_MAX, cifs_sb->local_nls,
2576 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002577 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2578 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002579 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002580 name_len = strnlen(from_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002581 name_len++; /* trailing null */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002582 strncpy(pSMB->OldFileName, from_name, name_len);
2583 name_len2 = strnlen(to_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002584 name_len2++; /* trailing null */
2585 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002586 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002587 name_len2++; /* trailing null */
2588 name_len2++; /* signature byte */
2589 }
2590
2591 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002592 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002593 pSMB->ByteCount = cpu_to_le16(count);
2594
2595 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2596 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002597 cifs_stats_inc(&tcon->stats.cifs_stats.num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002598 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002599 cFYI(1, "Send error in rename = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002600
Linus Torvalds1da177e2005-04-16 15:20:36 -07002601 cifs_buf_release(pSMB);
2602
2603 if (rc == -EAGAIN)
2604 goto renameRetry;
2605
2606 return rc;
2607}
2608
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002609int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002610 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002611 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002612{
2613 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2614 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002615 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002616 char *data_offset;
2617 char dummy_string[30];
2618 int rc = 0;
2619 int bytes_returned = 0;
2620 int len_of_str;
2621 __u16 params, param_offset, offset, count, byte_count;
2622
Joe Perchesb6b38f72010-04-21 03:50:45 +00002623 cFYI(1, "Rename to File by handle");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002624 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2625 (void **) &pSMBr);
2626 if (rc)
2627 return rc;
2628
2629 params = 6;
2630 pSMB->MaxSetupCount = 0;
2631 pSMB->Reserved = 0;
2632 pSMB->Flags = 0;
2633 pSMB->Timeout = 0;
2634 pSMB->Reserved2 = 0;
2635 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2636 offset = param_offset + params;
2637
2638 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2639 rename_info = (struct set_file_rename *) data_offset;
2640 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002641 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002642 pSMB->SetupCount = 1;
2643 pSMB->Reserved3 = 0;
2644 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2645 byte_count = 3 /* pad */ + params;
2646 pSMB->ParameterCount = cpu_to_le16(params);
2647 pSMB->TotalParameterCount = pSMB->ParameterCount;
2648 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2649 pSMB->DataOffset = cpu_to_le16(offset);
2650 /* construct random name ".cifs_tmp<inodenum><mid>" */
2651 rename_info->overwrite = cpu_to_le32(1);
2652 rename_info->root_fid = 0;
2653 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002654 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002655 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
Steve Frenchacbbb762012-01-18 22:32:33 -06002656 len_of_str =
2657 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002658 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002659 } else {
Steve Frenchacbbb762012-01-18 22:32:33 -06002660 len_of_str =
2661 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002662 target_name, PATH_MAX, nls_codepage,
2663 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002664 }
2665 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002666 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002667 byte_count += count;
2668 pSMB->DataCount = cpu_to_le16(count);
2669 pSMB->TotalDataCount = pSMB->DataCount;
2670 pSMB->Fid = netfid;
2671 pSMB->InformationLevel =
2672 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2673 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002674 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002675 pSMB->ByteCount = cpu_to_le16(byte_count);
2676 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002677 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002678 cifs_stats_inc(&pTcon->stats.cifs_stats.num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002679 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002680 cFYI(1, "Send error in Rename (by file handle) = %d", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07002681
Linus Torvalds1da177e2005-04-16 15:20:36 -07002682 cifs_buf_release(pSMB);
2683
2684 /* Note: On -EAGAIN error only caller can retry on handle based calls
2685 since file handle passed in no longer valid */
2686
2687 return rc;
2688}
2689
2690int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002691CIFSSMBCopy(const unsigned int xid, struct cifs_tcon *tcon,
2692 const char *fromName, const __u16 target_tid, const char *toName,
2693 const int flags, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002694{
2695 int rc = 0;
2696 COPY_REQ *pSMB = NULL;
2697 COPY_RSP *pSMBr = NULL;
2698 int bytes_returned;
2699 int name_len, name_len2;
2700 __u16 count;
2701
Joe Perchesb6b38f72010-04-21 03:50:45 +00002702 cFYI(1, "In CIFSSMBCopy");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002703copyRetry:
2704 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2705 (void **) &pSMBr);
2706 if (rc)
2707 return rc;
2708
2709 pSMB->BufferFormat = 0x04;
2710 pSMB->Tid2 = target_tid;
2711
2712 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2713
2714 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002715 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2716 fromName, PATH_MAX, nls_codepage,
2717 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002718 name_len++; /* trailing null */
2719 name_len *= 2;
2720 pSMB->OldFileName[name_len] = 0x04; /* pad */
2721 /* protocol requires ASCII signature byte on Unicode string */
2722 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002723 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002724 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2725 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002726 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2727 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002728 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002729 name_len = strnlen(fromName, PATH_MAX);
2730 name_len++; /* trailing null */
2731 strncpy(pSMB->OldFileName, fromName, name_len);
2732 name_len2 = strnlen(toName, PATH_MAX);
2733 name_len2++; /* trailing null */
2734 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2735 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2736 name_len2++; /* trailing null */
2737 name_len2++; /* signature byte */
2738 }
2739
2740 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002741 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002742 pSMB->ByteCount = cpu_to_le16(count);
2743
2744 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2745 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2746 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002747 cFYI(1, "Send error in copy = %d with %d files copied",
2748 rc, le16_to_cpu(pSMBr->CopyCount));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002749 }
Steve French0d817bc2008-05-22 02:02:03 +00002750 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002751
2752 if (rc == -EAGAIN)
2753 goto copyRetry;
2754
2755 return rc;
2756}
2757
2758int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002759CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002760 const char *fromName, const char *toName,
2761 const struct nls_table *nls_codepage)
2762{
2763 TRANSACTION2_SPI_REQ *pSMB = NULL;
2764 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2765 char *data_offset;
2766 int name_len;
2767 int name_len_target;
2768 int rc = 0;
2769 int bytes_returned = 0;
2770 __u16 params, param_offset, offset, byte_count;
2771
Joe Perchesb6b38f72010-04-21 03:50:45 +00002772 cFYI(1, "In Symlink Unix style");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002773createSymLinkRetry:
2774 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2775 (void **) &pSMBr);
2776 if (rc)
2777 return rc;
2778
2779 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2780 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06002781 cifs_strtoUTF16((__le16 *) pSMB->FileName, fromName,
2782 /* find define for this maxpathcomponent */
2783 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002784 name_len++; /* trailing null */
2785 name_len *= 2;
2786
Steve French50c2f752007-07-13 00:33:32 +00002787 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002788 name_len = strnlen(fromName, PATH_MAX);
2789 name_len++; /* trailing null */
2790 strncpy(pSMB->FileName, fromName, name_len);
2791 }
2792 params = 6 + name_len;
2793 pSMB->MaxSetupCount = 0;
2794 pSMB->Reserved = 0;
2795 pSMB->Flags = 0;
2796 pSMB->Timeout = 0;
2797 pSMB->Reserved2 = 0;
2798 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002799 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002800 offset = param_offset + params;
2801
2802 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2803 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2804 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06002805 cifs_strtoUTF16((__le16 *) data_offset, toName, PATH_MAX
2806 /* find define for this maxpathcomponent */
2807 , nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002808 name_len_target++; /* trailing null */
2809 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002810 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002811 name_len_target = strnlen(toName, PATH_MAX);
2812 name_len_target++; /* trailing null */
2813 strncpy(data_offset, toName, name_len_target);
2814 }
2815
2816 pSMB->MaxParameterCount = cpu_to_le16(2);
2817 /* BB find exact max on data count below from sess */
2818 pSMB->MaxDataCount = cpu_to_le16(1000);
2819 pSMB->SetupCount = 1;
2820 pSMB->Reserved3 = 0;
2821 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2822 byte_count = 3 /* pad */ + params + name_len_target;
2823 pSMB->DataCount = cpu_to_le16(name_len_target);
2824 pSMB->ParameterCount = cpu_to_le16(params);
2825 pSMB->TotalDataCount = pSMB->DataCount;
2826 pSMB->TotalParameterCount = pSMB->ParameterCount;
2827 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2828 pSMB->DataOffset = cpu_to_le16(offset);
2829 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2830 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002831 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832 pSMB->ByteCount = cpu_to_le16(byte_count);
2833 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2834 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002835 cifs_stats_inc(&tcon->stats.cifs_stats.num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002836 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002837 cFYI(1, "Send error in SetPathInfo create symlink = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002838
Steve French0d817bc2008-05-22 02:02:03 +00002839 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002840
2841 if (rc == -EAGAIN)
2842 goto createSymLinkRetry;
2843
2844 return rc;
2845}
2846
2847int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002848CIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002849 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002850 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002851{
2852 TRANSACTION2_SPI_REQ *pSMB = NULL;
2853 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2854 char *data_offset;
2855 int name_len;
2856 int name_len_target;
2857 int rc = 0;
2858 int bytes_returned = 0;
2859 __u16 params, param_offset, offset, byte_count;
2860
Joe Perchesb6b38f72010-04-21 03:50:45 +00002861 cFYI(1, "In Create Hard link Unix style");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002862createHardLinkRetry:
2863 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2864 (void **) &pSMBr);
2865 if (rc)
2866 return rc;
2867
2868 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002869 name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, toName,
2870 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002871 name_len++; /* trailing null */
2872 name_len *= 2;
2873
Steve French50c2f752007-07-13 00:33:32 +00002874 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002875 name_len = strnlen(toName, PATH_MAX);
2876 name_len++; /* trailing null */
2877 strncpy(pSMB->FileName, toName, name_len);
2878 }
2879 params = 6 + name_len;
2880 pSMB->MaxSetupCount = 0;
2881 pSMB->Reserved = 0;
2882 pSMB->Flags = 0;
2883 pSMB->Timeout = 0;
2884 pSMB->Reserved2 = 0;
2885 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002886 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002887 offset = param_offset + params;
2888
2889 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2890 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2891 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06002892 cifsConvertToUTF16((__le16 *) data_offset, fromName,
2893 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002894 name_len_target++; /* trailing null */
2895 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002896 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002897 name_len_target = strnlen(fromName, PATH_MAX);
2898 name_len_target++; /* trailing null */
2899 strncpy(data_offset, fromName, name_len_target);
2900 }
2901
2902 pSMB->MaxParameterCount = cpu_to_le16(2);
2903 /* BB find exact max on data count below from sess*/
2904 pSMB->MaxDataCount = cpu_to_le16(1000);
2905 pSMB->SetupCount = 1;
2906 pSMB->Reserved3 = 0;
2907 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2908 byte_count = 3 /* pad */ + params + name_len_target;
2909 pSMB->ParameterCount = cpu_to_le16(params);
2910 pSMB->TotalParameterCount = pSMB->ParameterCount;
2911 pSMB->DataCount = cpu_to_le16(name_len_target);
2912 pSMB->TotalDataCount = pSMB->DataCount;
2913 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2914 pSMB->DataOffset = cpu_to_le16(offset);
2915 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2916 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002917 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002918 pSMB->ByteCount = cpu_to_le16(byte_count);
2919 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2920 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002921 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002922 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002923 cFYI(1, "Send error in SetPathInfo (hard link) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002924
2925 cifs_buf_release(pSMB);
2926 if (rc == -EAGAIN)
2927 goto createHardLinkRetry;
2928
2929 return rc;
2930}
2931
2932int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002933CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchd6e906f2012-09-18 16:20:31 -07002934 const char *from_name, const char *to_name,
2935 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002936{
2937 int rc = 0;
2938 NT_RENAME_REQ *pSMB = NULL;
2939 RENAME_RSP *pSMBr = NULL;
2940 int bytes_returned;
2941 int name_len, name_len2;
2942 __u16 count;
Steve Frenchd6e906f2012-09-18 16:20:31 -07002943 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002944
Joe Perchesb6b38f72010-04-21 03:50:45 +00002945 cFYI(1, "In CIFSCreateHardLink");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002946winCreateHardLinkRetry:
2947
2948 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2949 (void **) &pSMBr);
2950 if (rc)
2951 return rc;
2952
2953 pSMB->SearchAttributes =
2954 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2955 ATTR_DIRECTORY);
2956 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2957 pSMB->ClusterCount = 0;
2958
2959 pSMB->BufferFormat = 0x04;
2960
2961 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2962 name_len =
Steve Frenchd6e906f2012-09-18 16:20:31 -07002963 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, from_name,
2964 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002965 name_len++; /* trailing null */
2966 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05002967
2968 /* protocol specifies ASCII buffer format (0x04) for unicode */
2969 pSMB->OldFileName[name_len] = 0x04;
2970 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002971 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002972 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Steve Frenchd6e906f2012-09-18 16:20:31 -07002973 to_name, PATH_MAX, cifs_sb->local_nls,
2974 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002975 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2976 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002977 } else { /* BB improve the check for buffer overruns BB */
Steve Frenchd6e906f2012-09-18 16:20:31 -07002978 name_len = strnlen(from_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002979 name_len++; /* trailing null */
Steve Frenchd6e906f2012-09-18 16:20:31 -07002980 strncpy(pSMB->OldFileName, from_name, name_len);
2981 name_len2 = strnlen(to_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002982 name_len2++; /* trailing null */
2983 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Steve Frenchd6e906f2012-09-18 16:20:31 -07002984 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002985 name_len2++; /* trailing null */
2986 name_len2++; /* signature byte */
2987 }
2988
2989 count = 1 /* string type byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002990 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002991 pSMB->ByteCount = cpu_to_le16(count);
2992
2993 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2994 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002995 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002996 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002997 cFYI(1, "Send error in hard link (NT rename) = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00002998
Linus Torvalds1da177e2005-04-16 15:20:36 -07002999 cifs_buf_release(pSMB);
3000 if (rc == -EAGAIN)
3001 goto winCreateHardLinkRetry;
3002
3003 return rc;
3004}
3005
3006int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003007CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04003008 const unsigned char *searchName, char **symlinkinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003009 const struct nls_table *nls_codepage)
3010{
3011/* SMB_QUERY_FILE_UNIX_LINK */
3012 TRANSACTION2_QPI_REQ *pSMB = NULL;
3013 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3014 int rc = 0;
3015 int bytes_returned;
3016 int name_len;
3017 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04003018 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003019
Joe Perchesb6b38f72010-04-21 03:50:45 +00003020 cFYI(1, "In QPathSymLinkInfo (Unix) for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003021
3022querySymLinkRetry:
3023 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3024 (void **) &pSMBr);
3025 if (rc)
3026 return rc;
3027
3028 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3029 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003030 cifs_strtoUTF16((__le16 *) pSMB->FileName, searchName,
3031 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003032 name_len++; /* trailing null */
3033 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003034 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003035 name_len = strnlen(searchName, PATH_MAX);
3036 name_len++; /* trailing null */
3037 strncpy(pSMB->FileName, searchName, name_len);
3038 }
3039
3040 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3041 pSMB->TotalDataCount = 0;
3042 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04003043 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003044 pSMB->MaxSetupCount = 0;
3045 pSMB->Reserved = 0;
3046 pSMB->Flags = 0;
3047 pSMB->Timeout = 0;
3048 pSMB->Reserved2 = 0;
3049 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003050 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003051 pSMB->DataCount = 0;
3052 pSMB->DataOffset = 0;
3053 pSMB->SetupCount = 1;
3054 pSMB->Reserved3 = 0;
3055 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3056 byte_count = params + 1 /* pad */ ;
3057 pSMB->TotalParameterCount = cpu_to_le16(params);
3058 pSMB->ParameterCount = pSMB->TotalParameterCount;
3059 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
3060 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003061 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003062 pSMB->ByteCount = cpu_to_le16(byte_count);
3063
3064 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3065 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3066 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003067 cFYI(1, "Send error in QuerySymLinkInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003068 } else {
3069 /* decode response */
3070
3071 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003072 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003073 if (rc || get_bcc(&pSMBr->hdr) < 2)
Jeff Layton460b9692009-04-30 07:17:56 -04003074 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003075 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00003076 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04003077 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003078
Jeff Layton460b9692009-04-30 07:17:56 -04003079 data_start = ((char *) &pSMBr->hdr.Protocol) +
3080 le16_to_cpu(pSMBr->t2.DataOffset);
3081
Steve French0e0d2cf2009-05-01 05:27:32 +00003082 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3083 is_unicode = true;
3084 else
3085 is_unicode = false;
3086
Steve French737b7582005-04-28 22:41:06 -07003087 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchacbbb762012-01-18 22:32:33 -06003088 *symlinkinfo = cifs_strndup_from_utf16(data_start,
3089 count, is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04003090 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04003091 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003092 }
3093 }
3094 cifs_buf_release(pSMB);
3095 if (rc == -EAGAIN)
3096 goto querySymLinkRetry;
3097 return rc;
3098}
3099
Steve Frenchc52a9552011-02-24 06:16:22 +00003100#ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL
3101/*
3102 * Recent Windows versions now create symlinks more frequently
3103 * and they use the "reparse point" mechanism below. We can of course
3104 * do symlinks nicely to Samba and other servers which support the
3105 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
3106 * "MF" symlinks optionally, but for recent Windows we really need to
3107 * reenable the code below and fix the cifs_symlink callers to handle this.
3108 * In the interim this code has been moved to its own config option so
3109 * it is not compiled in by default until callers fixed up and more tested.
3110 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003111int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003112CIFSSMBQueryReparseLinkInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003113 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00003114 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003115 const struct nls_table *nls_codepage)
3116{
3117 int rc = 0;
3118 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00003119 struct smb_com_transaction_ioctl_req *pSMB;
3120 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003121
Joe Perchesb6b38f72010-04-21 03:50:45 +00003122 cFYI(1, "In Windows reparse style QueryLink for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003123 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3124 (void **) &pSMBr);
3125 if (rc)
3126 return rc;
3127
3128 pSMB->TotalParameterCount = 0 ;
3129 pSMB->TotalDataCount = 0;
3130 pSMB->MaxParameterCount = cpu_to_le32(2);
3131 /* BB find exact data count max from sess structure BB */
Jeff Laytonc974bef2011-10-11 06:41:32 -04003132 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003133 pSMB->MaxSetupCount = 4;
3134 pSMB->Reserved = 0;
3135 pSMB->ParameterOffset = 0;
3136 pSMB->DataCount = 0;
3137 pSMB->DataOffset = 0;
3138 pSMB->SetupCount = 4;
3139 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
3140 pSMB->ParameterCount = pSMB->TotalParameterCount;
3141 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
3142 pSMB->IsFsctl = 1; /* FSCTL */
3143 pSMB->IsRootFlag = 0;
3144 pSMB->Fid = fid; /* file handle always le */
3145 pSMB->ByteCount = 0;
3146
3147 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3148 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3149 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003150 cFYI(1, "Send error in QueryReparseLinkInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003151 } else { /* decode response */
3152 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
3153 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
Jeff Layton820a8032011-05-04 08:05:26 -04003154 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
3155 /* BB also check enough total bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003156 rc = -EIO; /* bad smb */
Steve Frenchafe48c32009-05-02 05:25:46 +00003157 goto qreparse_out;
3158 }
3159 if (data_count && (data_count < 2048)) {
3160 char *end_of_smb = 2 /* sizeof byte count */ +
Jeff Layton820a8032011-05-04 08:05:26 -04003161 get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003162
Steve Frenchafe48c32009-05-02 05:25:46 +00003163 struct reparse_data *reparse_buf =
Steve French50c2f752007-07-13 00:33:32 +00003164 (struct reparse_data *)
3165 ((char *)&pSMBr->hdr.Protocol
3166 + data_offset);
Steve Frenchafe48c32009-05-02 05:25:46 +00003167 if ((char *)reparse_buf >= end_of_smb) {
3168 rc = -EIO;
3169 goto qreparse_out;
3170 }
3171 if ((reparse_buf->LinkNamesBuf +
3172 reparse_buf->TargetNameOffset +
3173 reparse_buf->TargetNameLen) > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003174 cFYI(1, "reparse buf beyond SMB");
Steve Frenchafe48c32009-05-02 05:25:46 +00003175 rc = -EIO;
3176 goto qreparse_out;
3177 }
Steve French50c2f752007-07-13 00:33:32 +00003178
Steve Frenchafe48c32009-05-02 05:25:46 +00003179 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3180 cifs_from_ucs2(symlinkinfo, (__le16 *)
Steve French50c2f752007-07-13 00:33:32 +00003181 (reparse_buf->LinkNamesBuf +
3182 reparse_buf->TargetNameOffset),
Steve Frenchafe48c32009-05-02 05:25:46 +00003183 buflen,
3184 reparse_buf->TargetNameLen,
3185 nls_codepage, 0);
3186 } else { /* ASCII names */
3187 strncpy(symlinkinfo,
3188 reparse_buf->LinkNamesBuf +
3189 reparse_buf->TargetNameOffset,
3190 min_t(const int, buflen,
3191 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003192 }
Steve Frenchafe48c32009-05-02 05:25:46 +00003193 } else {
3194 rc = -EIO;
Joe Perchesb6b38f72010-04-21 03:50:45 +00003195 cFYI(1, "Invalid return data count on "
3196 "get reparse info ioctl");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003197 }
Steve Frenchafe48c32009-05-02 05:25:46 +00003198 symlinkinfo[buflen] = 0; /* just in case so the caller
3199 does not go off the end of the buffer */
Joe Perchesb6b38f72010-04-21 03:50:45 +00003200 cFYI(1, "readlink result - %s", symlinkinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003201 }
Steve French989c7e52009-05-02 05:32:20 +00003202
Linus Torvalds1da177e2005-04-16 15:20:36 -07003203qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07003204 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003205
3206 /* Note: On -EAGAIN error only caller can retry on handle based calls
3207 since file handle passed in no longer valid */
3208
3209 return rc;
3210}
Steve Frenchc52a9552011-02-24 06:16:22 +00003211#endif /* CIFS_SYMLINK_EXPERIMENTAL */ /* BB temporarily unused */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003212
3213#ifdef CONFIG_CIFS_POSIX
3214
3215/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00003216static void cifs_convert_ace(posix_acl_xattr_entry *ace,
3217 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003218{
3219 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08003220 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
3221 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
3222 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesb6b38f72010-04-21 03:50:45 +00003223 /* cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003224
3225 return;
3226}
3227
3228/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00003229static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
3230 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003231{
3232 int size = 0;
3233 int i;
3234 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00003235 struct cifs_posix_ace *pACE;
3236 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
3237 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003238
3239 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
3240 return -EOPNOTSUPP;
3241
Steve French790fe572007-07-07 19:25:05 +00003242 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003243 count = le16_to_cpu(cifs_acl->access_entry_count);
3244 pACE = &cifs_acl->ace_array[0];
3245 size = sizeof(struct cifs_posix_acl);
3246 size += sizeof(struct cifs_posix_ace) * count;
3247 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003248 if (size_of_data_area < size) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003249 cFYI(1, "bad CIFS POSIX ACL size %d vs. %d",
3250 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003251 return -EINVAL;
3252 }
Steve French790fe572007-07-07 19:25:05 +00003253 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003254 count = le16_to_cpu(cifs_acl->access_entry_count);
3255 size = sizeof(struct cifs_posix_acl);
3256 size += sizeof(struct cifs_posix_ace) * count;
3257/* skip past access ACEs to get to default ACEs */
3258 pACE = &cifs_acl->ace_array[count];
3259 count = le16_to_cpu(cifs_acl->default_entry_count);
3260 size += sizeof(struct cifs_posix_ace) * count;
3261 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003262 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003263 return -EINVAL;
3264 } else {
3265 /* illegal type */
3266 return -EINVAL;
3267 }
3268
3269 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00003270 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00003271 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00003272 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003273 return -ERANGE;
3274 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08003275 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00003276 for (i = 0; i < count ; i++) {
3277 cifs_convert_ace(&local_acl->a_entries[i], pACE);
3278 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003279 }
3280 }
3281 return size;
3282}
3283
Steve French50c2f752007-07-13 00:33:32 +00003284static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
3285 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003286{
3287 __u16 rc = 0; /* 0 = ACL converted ok */
3288
Steve Frenchff7feac2005-11-15 16:45:16 -08003289 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
3290 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003291 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00003292 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003293 /* Probably no need to le convert -1 on any arch but can not hurt */
3294 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00003295 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08003296 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesb6b38f72010-04-21 03:50:45 +00003297 /*cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id);*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003298 return rc;
3299}
3300
3301/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00003302static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
3303 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003304{
3305 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00003306 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
3307 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003308 int count;
3309 int i;
3310
Steve French790fe572007-07-07 19:25:05 +00003311 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003312 return 0;
3313
3314 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesb6b38f72010-04-21 03:50:45 +00003315 cFYI(1, "setting acl with %d entries from buf of length %d and "
Steve French63135e02007-07-17 17:34:02 +00003316 "version of %d",
Joe Perchesb6b38f72010-04-21 03:50:45 +00003317 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00003318 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003319 cFYI(1, "unknown POSIX ACL version %d",
3320 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003321 return 0;
3322 }
3323 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00003324 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08003325 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00003326 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08003327 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003328 else {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003329 cFYI(1, "unknown ACL type %d", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003330 return 0;
3331 }
Steve French50c2f752007-07-13 00:33:32 +00003332 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003333 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
3334 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00003335 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003336 /* ACE not converted */
3337 break;
3338 }
3339 }
Steve French790fe572007-07-07 19:25:05 +00003340 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003341 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
3342 rc += sizeof(struct cifs_posix_acl);
3343 /* BB add check to make sure ACL does not overflow SMB */
3344 }
3345 return rc;
3346}
3347
3348int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003349CIFSSMBGetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003350 const unsigned char *searchName,
3351 char *acl_inf, const int buflen, const int acl_type,
3352 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003353{
3354/* SMB_QUERY_POSIX_ACL */
3355 TRANSACTION2_QPI_REQ *pSMB = NULL;
3356 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3357 int rc = 0;
3358 int bytes_returned;
3359 int name_len;
3360 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00003361
Joe Perchesb6b38f72010-04-21 03:50:45 +00003362 cFYI(1, "In GetPosixACL (Unix) for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003363
3364queryAclRetry:
3365 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3366 (void **) &pSMBr);
3367 if (rc)
3368 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003369
Linus Torvalds1da177e2005-04-16 15:20:36 -07003370 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3371 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003372 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3373 searchName, PATH_MAX, nls_codepage,
3374 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003375 name_len++; /* trailing null */
3376 name_len *= 2;
3377 pSMB->FileName[name_len] = 0;
3378 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00003379 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003380 name_len = strnlen(searchName, PATH_MAX);
3381 name_len++; /* trailing null */
3382 strncpy(pSMB->FileName, searchName, name_len);
3383 }
3384
3385 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3386 pSMB->TotalDataCount = 0;
3387 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00003388 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003389 pSMB->MaxDataCount = cpu_to_le16(4000);
3390 pSMB->MaxSetupCount = 0;
3391 pSMB->Reserved = 0;
3392 pSMB->Flags = 0;
3393 pSMB->Timeout = 0;
3394 pSMB->Reserved2 = 0;
3395 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003396 offsetof(struct smb_com_transaction2_qpi_req,
3397 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003398 pSMB->DataCount = 0;
3399 pSMB->DataOffset = 0;
3400 pSMB->SetupCount = 1;
3401 pSMB->Reserved3 = 0;
3402 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3403 byte_count = params + 1 /* pad */ ;
3404 pSMB->TotalParameterCount = cpu_to_le16(params);
3405 pSMB->ParameterCount = pSMB->TotalParameterCount;
3406 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
3407 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003408 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003409 pSMB->ByteCount = cpu_to_le16(byte_count);
3410
3411 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3412 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003413 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003414 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003415 cFYI(1, "Send error in Query POSIX ACL = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003416 } else {
3417 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00003418
Linus Torvalds1da177e2005-04-16 15:20:36 -07003419 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003420 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003421 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003422 rc = -EIO; /* bad smb */
3423 else {
3424 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3425 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3426 rc = cifs_copy_posix_acl(acl_inf,
3427 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00003428 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003429 }
3430 }
3431 cifs_buf_release(pSMB);
3432 if (rc == -EAGAIN)
3433 goto queryAclRetry;
3434 return rc;
3435}
3436
3437int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003438CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003439 const unsigned char *fileName,
3440 const char *local_acl, const int buflen,
3441 const int acl_type,
3442 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003443{
3444 struct smb_com_transaction2_spi_req *pSMB = NULL;
3445 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3446 char *parm_data;
3447 int name_len;
3448 int rc = 0;
3449 int bytes_returned = 0;
3450 __u16 params, byte_count, data_count, param_offset, offset;
3451
Joe Perchesb6b38f72010-04-21 03:50:45 +00003452 cFYI(1, "In SetPosixACL (Unix) for path %s", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003453setAclRetry:
3454 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003455 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003456 if (rc)
3457 return rc;
3458 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3459 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003460 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
3461 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003462 name_len++; /* trailing null */
3463 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003464 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003465 name_len = strnlen(fileName, PATH_MAX);
3466 name_len++; /* trailing null */
3467 strncpy(pSMB->FileName, fileName, name_len);
3468 }
3469 params = 6 + name_len;
3470 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003471 /* BB find max SMB size from sess */
3472 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003473 pSMB->MaxSetupCount = 0;
3474 pSMB->Reserved = 0;
3475 pSMB->Flags = 0;
3476 pSMB->Timeout = 0;
3477 pSMB->Reserved2 = 0;
3478 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003479 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003480 offset = param_offset + params;
3481 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
3482 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3483
3484 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00003485 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003486
Steve French790fe572007-07-07 19:25:05 +00003487 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003488 rc = -EOPNOTSUPP;
3489 goto setACLerrorExit;
3490 }
3491 pSMB->DataOffset = cpu_to_le16(offset);
3492 pSMB->SetupCount = 1;
3493 pSMB->Reserved3 = 0;
3494 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3495 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
3496 byte_count = 3 /* pad */ + params + data_count;
3497 pSMB->DataCount = cpu_to_le16(data_count);
3498 pSMB->TotalDataCount = pSMB->DataCount;
3499 pSMB->ParameterCount = cpu_to_le16(params);
3500 pSMB->TotalParameterCount = pSMB->ParameterCount;
3501 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003502 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003503 pSMB->ByteCount = cpu_to_le16(byte_count);
3504 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003505 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003506 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003507 cFYI(1, "Set POSIX ACL returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003508
3509setACLerrorExit:
3510 cifs_buf_release(pSMB);
3511 if (rc == -EAGAIN)
3512 goto setAclRetry;
3513 return rc;
3514}
3515
Steve Frenchf654bac2005-04-28 22:41:04 -07003516/* BB fix tabs in this function FIXME BB */
3517int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003518CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00003519 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07003520{
Steve French50c2f752007-07-13 00:33:32 +00003521 int rc = 0;
3522 struct smb_t2_qfi_req *pSMB = NULL;
3523 struct smb_t2_qfi_rsp *pSMBr = NULL;
3524 int bytes_returned;
3525 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07003526
Joe Perchesb6b38f72010-04-21 03:50:45 +00003527 cFYI(1, "In GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00003528 if (tcon == NULL)
3529 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07003530
3531GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003532 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3533 (void **) &pSMBr);
3534 if (rc)
3535 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003536
Steve Frenchad7a2922008-02-07 23:25:02 +00003537 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003538 pSMB->t2.TotalDataCount = 0;
3539 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3540 /* BB find exact max data count below from sess structure BB */
3541 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3542 pSMB->t2.MaxSetupCount = 0;
3543 pSMB->t2.Reserved = 0;
3544 pSMB->t2.Flags = 0;
3545 pSMB->t2.Timeout = 0;
3546 pSMB->t2.Reserved2 = 0;
3547 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3548 Fid) - 4);
3549 pSMB->t2.DataCount = 0;
3550 pSMB->t2.DataOffset = 0;
3551 pSMB->t2.SetupCount = 1;
3552 pSMB->t2.Reserved3 = 0;
3553 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3554 byte_count = params + 1 /* pad */ ;
3555 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3556 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3557 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3558 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003559 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003560 inc_rfc1001_len(pSMB, byte_count);
Steve French790fe572007-07-07 19:25:05 +00003561 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003562
Steve French790fe572007-07-07 19:25:05 +00003563 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3564 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3565 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003566 cFYI(1, "error %d in GetExtAttr", rc);
Steve French790fe572007-07-07 19:25:05 +00003567 } else {
3568 /* decode response */
3569 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003570 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003571 if (rc || get_bcc(&pSMBr->hdr) < 2)
Steve French790fe572007-07-07 19:25:05 +00003572 /* If rc should we check for EOPNOSUPP and
3573 disable the srvino flag? or in caller? */
3574 rc = -EIO; /* bad smb */
3575 else {
3576 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3577 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3578 struct file_chattr_info *pfinfo;
3579 /* BB Do we need a cast or hash here ? */
3580 if (count != 16) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003581 cFYI(1, "Illegal size ret in GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00003582 rc = -EIO;
3583 goto GetExtAttrOut;
3584 }
3585 pfinfo = (struct file_chattr_info *)
3586 (data_offset + (char *) &pSMBr->hdr.Protocol);
3587 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003588 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003589 }
3590 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003591GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003592 cifs_buf_release(pSMB);
3593 if (rc == -EAGAIN)
3594 goto GetExtAttrRetry;
3595 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003596}
3597
Steve Frenchf654bac2005-04-28 22:41:04 -07003598#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003599
Jeff Layton79df1ba2010-12-06 12:52:08 -05003600#ifdef CONFIG_CIFS_ACL
3601/*
3602 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3603 * all NT TRANSACTS that we init here have total parm and data under about 400
3604 * bytes (to fit in small cifs buffer size), which is the case so far, it
3605 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3606 * returned setup area) and MaxParameterCount (returned parms size) must be set
3607 * by caller
3608 */
3609static int
3610smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French96daf2b2011-05-27 04:34:02 +00003611 const int parm_len, struct cifs_tcon *tcon,
Jeff Layton79df1ba2010-12-06 12:52:08 -05003612 void **ret_buf)
3613{
3614 int rc;
3615 __u32 temp_offset;
3616 struct smb_com_ntransact_req *pSMB;
3617
3618 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3619 (void **)&pSMB);
3620 if (rc)
3621 return rc;
3622 *ret_buf = (void *)pSMB;
3623 pSMB->Reserved = 0;
3624 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3625 pSMB->TotalDataCount = 0;
Jeff Laytonc974bef2011-10-11 06:41:32 -04003626 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003627 pSMB->ParameterCount = pSMB->TotalParameterCount;
3628 pSMB->DataCount = pSMB->TotalDataCount;
3629 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3630 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3631 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3632 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3633 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3634 pSMB->SubCommand = cpu_to_le16(sub_command);
3635 return 0;
3636}
3637
3638static int
3639validate_ntransact(char *buf, char **ppparm, char **ppdata,
3640 __u32 *pparmlen, __u32 *pdatalen)
3641{
3642 char *end_of_smb;
3643 __u32 data_count, data_offset, parm_count, parm_offset;
3644 struct smb_com_ntransact_rsp *pSMBr;
Jeff Layton820a8032011-05-04 08:05:26 -04003645 u16 bcc;
Jeff Layton79df1ba2010-12-06 12:52:08 -05003646
3647 *pdatalen = 0;
3648 *pparmlen = 0;
3649
3650 if (buf == NULL)
3651 return -EINVAL;
3652
3653 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3654
Jeff Layton820a8032011-05-04 08:05:26 -04003655 bcc = get_bcc(&pSMBr->hdr);
3656 end_of_smb = 2 /* sizeof byte count */ + bcc +
Jeff Layton79df1ba2010-12-06 12:52:08 -05003657 (char *)&pSMBr->ByteCount;
3658
3659 data_offset = le32_to_cpu(pSMBr->DataOffset);
3660 data_count = le32_to_cpu(pSMBr->DataCount);
3661 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3662 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3663
3664 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3665 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3666
3667 /* should we also check that parm and data areas do not overlap? */
3668 if (*ppparm > end_of_smb) {
3669 cFYI(1, "parms start after end of smb");
3670 return -EINVAL;
3671 } else if (parm_count + *ppparm > end_of_smb) {
3672 cFYI(1, "parm end after end of smb");
3673 return -EINVAL;
3674 } else if (*ppdata > end_of_smb) {
3675 cFYI(1, "data starts after end of smb");
3676 return -EINVAL;
3677 } else if (data_count + *ppdata > end_of_smb) {
3678 cFYI(1, "data %p + count %d (%p) past smb end %p start %p",
3679 *ppdata, data_count, (data_count + *ppdata),
3680 end_of_smb, pSMBr);
3681 return -EINVAL;
Jeff Layton820a8032011-05-04 08:05:26 -04003682 } else if (parm_count + data_count > bcc) {
Jeff Layton79df1ba2010-12-06 12:52:08 -05003683 cFYI(1, "parm count and data count larger than SMB");
3684 return -EINVAL;
3685 }
3686 *pdatalen = data_count;
3687 *pparmlen = parm_count;
3688 return 0;
3689}
3690
Steve French0a4b92c2006-01-12 15:44:21 -08003691/* Get Security Descriptor (by handle) from remote server for a file or dir */
3692int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003693CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003694 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003695{
3696 int rc = 0;
3697 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003698 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003699 struct kvec iov[1];
3700
Joe Perchesb6b38f72010-04-21 03:50:45 +00003701 cFYI(1, "GetCifsACL");
Steve French0a4b92c2006-01-12 15:44:21 -08003702
Steve French630f3f0c2007-10-25 21:17:17 +00003703 *pbuflen = 0;
3704 *acl_inf = NULL;
3705
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003706 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003707 8 /* parm len */, tcon, (void **) &pSMB);
3708 if (rc)
3709 return rc;
3710
3711 pSMB->MaxParameterCount = cpu_to_le32(4);
3712 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3713 pSMB->MaxSetupCount = 0;
3714 pSMB->Fid = fid; /* file handle always le */
3715 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3716 CIFS_ACL_DACL);
3717 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003718 inc_rfc1001_len(pSMB, 11);
Steve French0a4b92c2006-01-12 15:44:21 -08003719 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003720 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French0a4b92c2006-01-12 15:44:21 -08003721
Steve Frencha761ac52007-10-18 21:45:27 +00003722 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Jeff Layton77499812011-01-11 07:24:23 -05003723 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003724 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Steve French0a4b92c2006-01-12 15:44:21 -08003725 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003726 cFYI(1, "Send error in QuerySecDesc = %d", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08003727 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003728 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003729 __u32 parm_len;
3730 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003731 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003732 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003733
3734/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003735 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003736 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003737 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003738 goto qsec_out;
3739 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3740
Joe Perchesb6b38f72010-04-21 03:50:45 +00003741 cFYI(1, "smb %p parm %p data %p", pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08003742
3743 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3744 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003745 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003746 goto qsec_out;
3747 }
3748
3749/* BB check that data area is minimum length and as big as acl_len */
3750
Steve Frenchaf6f4612007-10-16 18:40:37 +00003751 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003752 if (acl_len != *pbuflen) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003753 cERROR(1, "acl length %d does not match %d",
3754 acl_len, *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003755 if (*pbuflen > acl_len)
3756 *pbuflen = acl_len;
3757 }
Steve French0a4b92c2006-01-12 15:44:21 -08003758
Steve French630f3f0c2007-10-25 21:17:17 +00003759 /* check if buffer is big enough for the acl
3760 header followed by the smallest SID */
3761 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3762 (*pbuflen >= 64 * 1024)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003763 cERROR(1, "bad acl length %d", *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003764 rc = -EINVAL;
3765 *pbuflen = 0;
3766 } else {
3767 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3768 if (*acl_inf == NULL) {
3769 *pbuflen = 0;
3770 rc = -ENOMEM;
3771 }
3772 memcpy(*acl_inf, pdata, *pbuflen);
3773 }
Steve French0a4b92c2006-01-12 15:44:21 -08003774 }
3775qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003776 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003777 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003778 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003779 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003780/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003781 return rc;
3782}
Steve French97837582007-12-31 07:47:21 +00003783
3784int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003785CIFSSMBSetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003786 struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
Steve French97837582007-12-31 07:47:21 +00003787{
3788 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3789 int rc = 0;
3790 int bytes_returned = 0;
3791 SET_SEC_DESC_REQ *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003792 void *pSMBr;
Steve French97837582007-12-31 07:47:21 +00003793
3794setCifsAclRetry:
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003795 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, &pSMBr);
Steve French97837582007-12-31 07:47:21 +00003796 if (rc)
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003797 return rc;
Steve French97837582007-12-31 07:47:21 +00003798
3799 pSMB->MaxSetupCount = 0;
3800 pSMB->Reserved = 0;
3801
3802 param_count = 8;
3803 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3804 data_count = acllen;
3805 data_offset = param_offset + param_count;
3806 byte_count = 3 /* pad */ + param_count;
3807
3808 pSMB->DataCount = cpu_to_le32(data_count);
3809 pSMB->TotalDataCount = pSMB->DataCount;
3810 pSMB->MaxParameterCount = cpu_to_le32(4);
3811 pSMB->MaxDataCount = cpu_to_le32(16384);
3812 pSMB->ParameterCount = cpu_to_le32(param_count);
3813 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3814 pSMB->TotalParameterCount = pSMB->ParameterCount;
3815 pSMB->DataOffset = cpu_to_le32(data_offset);
3816 pSMB->SetupCount = 0;
3817 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3818 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3819
3820 pSMB->Fid = fid; /* file handle always le */
3821 pSMB->Reserved2 = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003822 pSMB->AclFlags = cpu_to_le32(aclflag);
Steve French97837582007-12-31 07:47:21 +00003823
3824 if (pntsd && acllen) {
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003825 memcpy((char *)pSMBr + offsetof(struct smb_hdr, Protocol) +
3826 data_offset, pntsd, acllen);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003827 inc_rfc1001_len(pSMB, byte_count + data_count);
Steve French97837582007-12-31 07:47:21 +00003828 } else
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003829 inc_rfc1001_len(pSMB, byte_count);
Steve French97837582007-12-31 07:47:21 +00003830
3831 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3832 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3833
Joe Perchesb6b38f72010-04-21 03:50:45 +00003834 cFYI(1, "SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00003835 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003836 cFYI(1, "Set CIFS ACL returned %d", rc);
Steve French97837582007-12-31 07:47:21 +00003837 cifs_buf_release(pSMB);
3838
3839 if (rc == -EAGAIN)
3840 goto setCifsAclRetry;
3841
3842 return (rc);
3843}
3844
Jeff Layton79df1ba2010-12-06 12:52:08 -05003845#endif /* CONFIG_CIFS_ACL */
Steve French0a4b92c2006-01-12 15:44:21 -08003846
Steve French6b8edfe2005-08-23 20:26:03 -07003847/* Legacy Query Path Information call for lookup to old servers such
3848 as Win9x/WinME */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003849int
3850SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon,
3851 const char *search_name, FILE_ALL_INFO *data,
3852 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003853{
Steve Frenchad7a2922008-02-07 23:25:02 +00003854 QUERY_INFORMATION_REQ *pSMB;
3855 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003856 int rc = 0;
3857 int bytes_returned;
3858 int name_len;
3859
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003860 cFYI(1, "In SMBQPath path %s", search_name);
Steve French6b8edfe2005-08-23 20:26:03 -07003861QInfRetry:
3862 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003863 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003864 if (rc)
3865 return rc;
3866
3867 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3868 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003869 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003870 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06003871 remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003872 name_len++; /* trailing null */
3873 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003874 } else {
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003875 name_len = strnlen(search_name, PATH_MAX);
Steve French6b8edfe2005-08-23 20:26:03 -07003876 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003877 strncpy(pSMB->FileName, search_name, name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07003878 }
3879 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003880 name_len++; /* account for buffer type byte */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003881 inc_rfc1001_len(pSMB, (__u16)name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07003882 pSMB->ByteCount = cpu_to_le16(name_len);
3883
3884 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003885 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003886 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003887 cFYI(1, "Send error in QueryInfo = %d", rc);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003888 } else if (data) {
Steve French1bd5bbc2006-09-28 03:35:57 +00003889 struct timespec ts;
3890 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00003891
3892 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003893 /* BB FIXME - add time zone adjustment BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003894 memset(data, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003895 ts.tv_nsec = 0;
3896 ts.tv_sec = time;
3897 /* decode time fields */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003898 data->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
3899 data->LastWriteTime = data->ChangeTime;
3900 data->LastAccessTime = 0;
3901 data->AllocationSize =
Steve French70ca7342005-09-22 16:32:06 -07003902 cpu_to_le64(le32_to_cpu(pSMBr->size));
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003903 data->EndOfFile = data->AllocationSize;
3904 data->Attributes =
Steve French70ca7342005-09-22 16:32:06 -07003905 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003906 } else
3907 rc = -EIO; /* bad buffer passed in */
3908
3909 cifs_buf_release(pSMB);
3910
3911 if (rc == -EAGAIN)
3912 goto QInfRetry;
3913
3914 return rc;
3915}
3916
Jeff Laytonbcd53572010-02-12 07:44:16 -05003917int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003918CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonbcd53572010-02-12 07:44:16 -05003919 u16 netfid, FILE_ALL_INFO *pFindData)
3920{
3921 struct smb_t2_qfi_req *pSMB = NULL;
3922 struct smb_t2_qfi_rsp *pSMBr = NULL;
3923 int rc = 0;
3924 int bytes_returned;
3925 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07003926
Jeff Laytonbcd53572010-02-12 07:44:16 -05003927QFileInfoRetry:
3928 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3929 (void **) &pSMBr);
3930 if (rc)
3931 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07003932
Jeff Laytonbcd53572010-02-12 07:44:16 -05003933 params = 2 /* level */ + 2 /* fid */;
3934 pSMB->t2.TotalDataCount = 0;
3935 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3936 /* BB find exact max data count below from sess structure BB */
3937 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3938 pSMB->t2.MaxSetupCount = 0;
3939 pSMB->t2.Reserved = 0;
3940 pSMB->t2.Flags = 0;
3941 pSMB->t2.Timeout = 0;
3942 pSMB->t2.Reserved2 = 0;
3943 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3944 Fid) - 4);
3945 pSMB->t2.DataCount = 0;
3946 pSMB->t2.DataOffset = 0;
3947 pSMB->t2.SetupCount = 1;
3948 pSMB->t2.Reserved3 = 0;
3949 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3950 byte_count = params + 1 /* pad */ ;
3951 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3952 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3953 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3954 pSMB->Pad = 0;
3955 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003956 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003957
3958 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3959 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3960 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00003961 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003962 } else { /* decode response */
3963 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3964
3965 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3966 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04003967 else if (get_bcc(&pSMBr->hdr) < 40)
Jeff Laytonbcd53572010-02-12 07:44:16 -05003968 rc = -EIO; /* bad smb */
3969 else if (pFindData) {
3970 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3971 memcpy((char *) pFindData,
3972 (char *) &pSMBr->hdr.Protocol +
3973 data_offset, sizeof(FILE_ALL_INFO));
3974 } else
3975 rc = -ENOMEM;
3976 }
3977 cifs_buf_release(pSMB);
3978 if (rc == -EAGAIN)
3979 goto QFileInfoRetry;
3980
3981 return rc;
3982}
Steve French6b8edfe2005-08-23 20:26:03 -07003983
Linus Torvalds1da177e2005-04-16 15:20:36 -07003984int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003985CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003986 const char *search_name, FILE_ALL_INFO *data,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003987 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003988 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003989{
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003990 /* level 263 SMB_QUERY_FILE_ALL_INFO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003991 TRANSACTION2_QPI_REQ *pSMB = NULL;
3992 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3993 int rc = 0;
3994 int bytes_returned;
3995 int name_len;
3996 __u16 params, byte_count;
3997
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003998 /* cFYI(1, "In QPathInfo path %s", search_name); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003999QPathInfoRetry:
4000 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4001 (void **) &pSMBr);
4002 if (rc)
4003 return rc;
4004
4005 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4006 name_len =
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004007 cifsConvertToUTF16((__le16 *) pSMB->FileName, search_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06004008 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004009 name_len++; /* trailing null */
4010 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004011 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004012 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004013 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004014 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004015 }
4016
Steve French50c2f752007-07-13 00:33:32 +00004017 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004018 pSMB->TotalDataCount = 0;
4019 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004020 /* BB find exact max SMB PDU from sess structure BB */
4021 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004022 pSMB->MaxSetupCount = 0;
4023 pSMB->Reserved = 0;
4024 pSMB->Flags = 0;
4025 pSMB->Timeout = 0;
4026 pSMB->Reserved2 = 0;
4027 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004028 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004029 pSMB->DataCount = 0;
4030 pSMB->DataOffset = 0;
4031 pSMB->SetupCount = 1;
4032 pSMB->Reserved3 = 0;
4033 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4034 byte_count = params + 1 /* pad */ ;
4035 pSMB->TotalParameterCount = cpu_to_le16(params);
4036 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00004037 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004038 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
4039 else
4040 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004041 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004042 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004043 pSMB->ByteCount = cpu_to_le16(byte_count);
4044
4045 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4046 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4047 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004048 cFYI(1, "Send error in QPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004049 } else { /* decode response */
4050 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4051
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004052 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4053 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004054 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004055 rc = -EIO; /* bad smb */
Jeff Layton820a8032011-05-04 08:05:26 -04004056 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
Steve French50c2f752007-07-13 00:33:32 +00004057 rc = -EIO; /* 24 or 26 expected but we do not read
4058 last field */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004059 else if (data) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004060 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004061 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00004062
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004063 /*
4064 * On legacy responses we do not read the last field,
4065 * EAsize, fortunately since it varies by subdialect and
4066 * also note it differs on Set vs Get, ie two bytes or 4
4067 * bytes depending but we don't care here.
4068 */
Steve Frenchad7a2922008-02-07 23:25:02 +00004069 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004070 size = sizeof(FILE_INFO_STANDARD);
4071 else
4072 size = sizeof(FILE_ALL_INFO);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004073 memcpy((char *) data, (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004074 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004075 } else
4076 rc = -ENOMEM;
4077 }
4078 cifs_buf_release(pSMB);
4079 if (rc == -EAGAIN)
4080 goto QPathInfoRetry;
4081
4082 return rc;
4083}
4084
4085int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004086CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004087 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
4088{
4089 struct smb_t2_qfi_req *pSMB = NULL;
4090 struct smb_t2_qfi_rsp *pSMBr = NULL;
4091 int rc = 0;
4092 int bytes_returned;
4093 __u16 params, byte_count;
4094
4095UnixQFileInfoRetry:
4096 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4097 (void **) &pSMBr);
4098 if (rc)
4099 return rc;
4100
4101 params = 2 /* level */ + 2 /* fid */;
4102 pSMB->t2.TotalDataCount = 0;
4103 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4104 /* BB find exact max data count below from sess structure BB */
4105 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4106 pSMB->t2.MaxSetupCount = 0;
4107 pSMB->t2.Reserved = 0;
4108 pSMB->t2.Flags = 0;
4109 pSMB->t2.Timeout = 0;
4110 pSMB->t2.Reserved2 = 0;
4111 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4112 Fid) - 4);
4113 pSMB->t2.DataCount = 0;
4114 pSMB->t2.DataOffset = 0;
4115 pSMB->t2.SetupCount = 1;
4116 pSMB->t2.Reserved3 = 0;
4117 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4118 byte_count = params + 1 /* pad */ ;
4119 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4120 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4121 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4122 pSMB->Pad = 0;
4123 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004124 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004125
4126 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4127 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4128 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00004129 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004130 } else { /* decode response */
4131 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4132
Jeff Layton820a8032011-05-04 08:05:26 -04004133 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004134 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response. "
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004135 "Unix Extensions can be disabled on mount "
Steve Frenchf19159d2010-04-21 04:12:10 +00004136 "by specifying the nosfu mount option.");
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004137 rc = -EIO; /* bad smb */
4138 } else {
4139 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4140 memcpy((char *) pFindData,
4141 (char *) &pSMBr->hdr.Protocol +
4142 data_offset,
4143 sizeof(FILE_UNIX_BASIC_INFO));
4144 }
4145 }
4146
4147 cifs_buf_release(pSMB);
4148 if (rc == -EAGAIN)
4149 goto UnixQFileInfoRetry;
4150
4151 return rc;
4152}
4153
4154int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004155CIFSSMBUnixQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004156 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00004157 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07004158 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004159{
4160/* SMB_QUERY_FILE_UNIX_BASIC */
4161 TRANSACTION2_QPI_REQ *pSMB = NULL;
4162 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4163 int rc = 0;
4164 int bytes_returned = 0;
4165 int name_len;
4166 __u16 params, byte_count;
4167
Joe Perchesb6b38f72010-04-21 03:50:45 +00004168 cFYI(1, "In QPathInfo (Unix) the path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004169UnixQPathInfoRetry:
4170 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4171 (void **) &pSMBr);
4172 if (rc)
4173 return rc;
4174
4175 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4176 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004177 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4178 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004179 name_len++; /* trailing null */
4180 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004181 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004182 name_len = strnlen(searchName, PATH_MAX);
4183 name_len++; /* trailing null */
4184 strncpy(pSMB->FileName, searchName, name_len);
4185 }
4186
Steve French50c2f752007-07-13 00:33:32 +00004187 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004188 pSMB->TotalDataCount = 0;
4189 pSMB->MaxParameterCount = cpu_to_le16(2);
4190 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00004191 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004192 pSMB->MaxSetupCount = 0;
4193 pSMB->Reserved = 0;
4194 pSMB->Flags = 0;
4195 pSMB->Timeout = 0;
4196 pSMB->Reserved2 = 0;
4197 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004198 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004199 pSMB->DataCount = 0;
4200 pSMB->DataOffset = 0;
4201 pSMB->SetupCount = 1;
4202 pSMB->Reserved3 = 0;
4203 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4204 byte_count = params + 1 /* pad */ ;
4205 pSMB->TotalParameterCount = cpu_to_le16(params);
4206 pSMB->ParameterCount = pSMB->TotalParameterCount;
4207 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4208 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004209 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004210 pSMB->ByteCount = cpu_to_le16(byte_count);
4211
4212 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4213 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4214 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004215 cFYI(1, "Send error in QPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004216 } else { /* decode response */
4217 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4218
Jeff Layton820a8032011-05-04 08:05:26 -04004219 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004220 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response. "
Steve French1e71f252007-09-20 15:30:07 +00004221 "Unix Extensions can be disabled on mount "
Joe Perchesb6b38f72010-04-21 03:50:45 +00004222 "by specifying the nosfu mount option.");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004223 rc = -EIO; /* bad smb */
4224 } else {
4225 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4226 memcpy((char *) pFindData,
4227 (char *) &pSMBr->hdr.Protocol +
4228 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00004229 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004230 }
4231 }
4232 cifs_buf_release(pSMB);
4233 if (rc == -EAGAIN)
4234 goto UnixQPathInfoRetry;
4235
4236 return rc;
4237}
4238
Linus Torvalds1da177e2005-04-16 15:20:36 -07004239/* xid, tcon, searchName and codepage are input parms, rest are returned */
4240int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004241CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004242 const char *searchName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004243 const struct nls_table *nls_codepage,
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004244 __u16 *pnetfid, __u16 search_flags,
Steve French50c2f752007-07-13 00:33:32 +00004245 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004246{
4247/* level 257 SMB_ */
4248 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
4249 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004250 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004251 int rc = 0;
4252 int bytes_returned = 0;
4253 int name_len;
4254 __u16 params, byte_count;
4255
Joe Perchesb6b38f72010-04-21 03:50:45 +00004256 cFYI(1, "In FindFirst for %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004257
4258findFirstRetry:
4259 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4260 (void **) &pSMBr);
4261 if (rc)
4262 return rc;
4263
4264 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4265 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004266 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4267 PATH_MAX, nls_codepage, remap);
Steve French737b7582005-04-28 22:41:06 -07004268 /* We can not add the asterik earlier in case
4269 it got remapped to 0xF03A as if it were part of the
4270 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004271 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07004272 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07004273 pSMB->FileName[name_len+1] = 0;
4274 pSMB->FileName[name_len+2] = '*';
4275 pSMB->FileName[name_len+3] = 0;
4276 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004277 pSMB->FileName[name_len] = 0; /* null terminate just in case */
4278 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07004279 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004280 } else { /* BB add check for overrun of SMB buf BB */
4281 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004282/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00004283 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004284 free buffer exit; BB */
4285 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07004286 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07004287 pSMB->FileName[name_len+1] = '*';
4288 pSMB->FileName[name_len+2] = 0;
4289 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004290 }
4291
4292 params = 12 + name_len /* includes null */ ;
4293 pSMB->TotalDataCount = 0; /* no EAs */
4294 pSMB->MaxParameterCount = cpu_to_le16(10);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004295 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004296 pSMB->MaxSetupCount = 0;
4297 pSMB->Reserved = 0;
4298 pSMB->Flags = 0;
4299 pSMB->Timeout = 0;
4300 pSMB->Reserved2 = 0;
4301 byte_count = params + 1 /* pad */ ;
4302 pSMB->TotalParameterCount = cpu_to_le16(params);
4303 pSMB->ParameterCount = pSMB->TotalParameterCount;
4304 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00004305 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
4306 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004307 pSMB->DataCount = 0;
4308 pSMB->DataOffset = 0;
4309 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
4310 pSMB->Reserved3 = 0;
4311 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
4312 pSMB->SearchAttributes =
4313 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
4314 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00004315 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004316 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004317 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4318
4319 /* BB what should we set StorageType to? Does it matter? BB */
4320 pSMB->SearchStorageType = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004321 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004322 pSMB->ByteCount = cpu_to_le16(byte_count);
4323
4324 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4325 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004326 cifs_stats_inc(&tcon->stats.cifs_stats.num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004327
Steve French88274812006-03-09 22:21:45 +00004328 if (rc) {/* BB add logic to retry regular search if Unix search
4329 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004330 /* BB Add code to handle unsupported level rc */
Joe Perchesb6b38f72010-04-21 03:50:45 +00004331 cFYI(1, "Error in FindFirst = %d", rc);
Steve French1982c342005-08-17 12:38:22 -07004332
Steve French88274812006-03-09 22:21:45 +00004333 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004334
4335 /* BB eventually could optimize out free and realloc of buf */
4336 /* for this case */
4337 if (rc == -EAGAIN)
4338 goto findFirstRetry;
4339 } else { /* decode response */
4340 /* BB remember to free buffer if error BB */
4341 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00004342 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004343 unsigned int lnoff;
4344
Linus Torvalds1da177e2005-04-16 15:20:36 -07004345 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004346 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004347 else
Steve French4b18f2a2008-04-29 00:06:05 +00004348 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004349
4350 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004351 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00004352 psrch_inf->srch_entries_start =
4353 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004354 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004355 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
4356 le16_to_cpu(pSMBr->t2.ParameterOffset));
4357
Steve French790fe572007-07-07 19:25:05 +00004358 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004359 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004360 else
Steve French4b18f2a2008-04-29 00:06:05 +00004361 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004362
Steve French50c2f752007-07-13 00:33:32 +00004363 psrch_inf->entries_in_buffer =
4364 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00004365 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004366 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004367 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004368 if (CIFSMaxBufSize < lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004369 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00004370 psrch_inf->last_entry = NULL;
4371 return rc;
4372 }
4373
Steve French0752f152008-10-07 20:03:33 +00004374 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00004375 lnoff;
4376
Linus Torvalds1da177e2005-04-16 15:20:36 -07004377 *pnetfid = parms->SearchHandle;
4378 } else {
4379 cifs_buf_release(pSMB);
4380 }
4381 }
4382
4383 return rc;
4384}
4385
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004386int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
4387 __u16 searchHandle, __u16 search_flags,
4388 struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004389{
4390 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
4391 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004392 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004393 char *response_data;
4394 int rc = 0;
Jeff Layton9438fab2011-08-23 07:21:28 -04004395 int bytes_returned;
4396 unsigned int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004397 __u16 params, byte_count;
4398
Joe Perchesb6b38f72010-04-21 03:50:45 +00004399 cFYI(1, "In FindNext");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004400
Steve French4b18f2a2008-04-29 00:06:05 +00004401 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004402 return -ENOENT;
4403
4404 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4405 (void **) &pSMBr);
4406 if (rc)
4407 return rc;
4408
Steve French50c2f752007-07-13 00:33:32 +00004409 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004410 byte_count = 0;
4411 pSMB->TotalDataCount = 0; /* no EAs */
4412 pSMB->MaxParameterCount = cpu_to_le16(8);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004413 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004414 pSMB->MaxSetupCount = 0;
4415 pSMB->Reserved = 0;
4416 pSMB->Flags = 0;
4417 pSMB->Timeout = 0;
4418 pSMB->Reserved2 = 0;
4419 pSMB->ParameterOffset = cpu_to_le16(
4420 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
4421 pSMB->DataCount = 0;
4422 pSMB->DataOffset = 0;
4423 pSMB->SetupCount = 1;
4424 pSMB->Reserved3 = 0;
4425 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
4426 pSMB->SearchHandle = searchHandle; /* always kept as le */
4427 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00004428 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004429 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4430 pSMB->ResumeKey = psrch_inf->resume_key;
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004431 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004432
4433 name_len = psrch_inf->resume_name_len;
4434 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00004435 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004436 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
4437 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07004438 /* 14 byte parm len above enough for 2 byte null terminator */
4439 pSMB->ResumeFileName[name_len] = 0;
4440 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004441 } else {
4442 rc = -EINVAL;
4443 goto FNext2_err_exit;
4444 }
4445 byte_count = params + 1 /* pad */ ;
4446 pSMB->TotalParameterCount = cpu_to_le16(params);
4447 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004448 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004449 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004450
Linus Torvalds1da177e2005-04-16 15:20:36 -07004451 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4452 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004453 cifs_stats_inc(&tcon->stats.cifs_stats.num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004454 if (rc) {
4455 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00004456 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07004457 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00004458 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004459 } else
Joe Perchesb6b38f72010-04-21 03:50:45 +00004460 cFYI(1, "FindNext returned = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004461 } else { /* decode response */
4462 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00004463
Steve French790fe572007-07-07 19:25:05 +00004464 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004465 unsigned int lnoff;
4466
Linus Torvalds1da177e2005-04-16 15:20:36 -07004467 /* BB fixme add lock for file (srch_info) struct here */
4468 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004469 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004470 else
Steve French4b18f2a2008-04-29 00:06:05 +00004471 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004472 response_data = (char *) &pSMBr->hdr.Protocol +
4473 le16_to_cpu(pSMBr->t2.ParameterOffset);
4474 parms = (T2_FNEXT_RSP_PARMS *)response_data;
4475 response_data = (char *)&pSMBr->hdr.Protocol +
4476 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00004477 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00004478 cifs_small_buf_release(
4479 psrch_inf->ntwrk_buf_start);
4480 else
4481 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004482 psrch_inf->srch_entries_start = response_data;
4483 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004484 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00004485 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004486 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004487 else
Steve French4b18f2a2008-04-29 00:06:05 +00004488 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00004489 psrch_inf->entries_in_buffer =
4490 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004491 psrch_inf->index_of_last_entry +=
4492 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004493 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004494 if (CIFSMaxBufSize < lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004495 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00004496 psrch_inf->last_entry = NULL;
4497 return rc;
4498 } else
4499 psrch_inf->last_entry =
4500 psrch_inf->srch_entries_start + lnoff;
4501
Joe Perchesb6b38f72010-04-21 03:50:45 +00004502/* cFYI(1, "fnxt2 entries in buf %d index_of_last %d",
4503 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004504
4505 /* BB fixme add unlock here */
4506 }
4507
4508 }
4509
4510 /* BB On error, should we leave previous search buf (and count and
4511 last entry fields) intact or free the previous one? */
4512
4513 /* Note: On -EAGAIN error only caller can retry on handle based calls
4514 since file handle passed in no longer valid */
4515FNext2_err_exit:
4516 if (rc != 0)
4517 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004518 return rc;
4519}
4520
4521int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004522CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004523 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004524{
4525 int rc = 0;
4526 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004527
Joe Perchesb6b38f72010-04-21 03:50:45 +00004528 cFYI(1, "In CIFSSMBFindClose");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004529 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
4530
4531 /* no sense returning error if session restarted
4532 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00004533 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004534 return 0;
4535 if (rc)
4536 return rc;
4537
Linus Torvalds1da177e2005-04-16 15:20:36 -07004538 pSMB->FileID = searchHandle;
4539 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04004540 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004541 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00004542 cERROR(1, "Send error in FindClose = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00004543
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004544 cifs_stats_inc(&tcon->stats.cifs_stats.num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004545
4546 /* Since session is dead, search handle closed on server already */
4547 if (rc == -EAGAIN)
4548 rc = 0;
4549
4550 return rc;
4551}
4552
Linus Torvalds1da177e2005-04-16 15:20:36 -07004553int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004554CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004555 const char *search_name, __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00004556 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004557{
4558 int rc = 0;
4559 TRANSACTION2_QPI_REQ *pSMB = NULL;
4560 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4561 int name_len, bytes_returned;
4562 __u16 params, byte_count;
4563
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004564 cFYI(1, "In GetSrvInodeNum for %s", search_name);
Steve French790fe572007-07-07 19:25:05 +00004565 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00004566 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004567
4568GetInodeNumberRetry:
4569 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004570 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004571 if (rc)
4572 return rc;
4573
Linus Torvalds1da177e2005-04-16 15:20:36 -07004574 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4575 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004576 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004577 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004578 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004579 name_len++; /* trailing null */
4580 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004581 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004582 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004583 name_len++; /* trailing null */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004584 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004585 }
4586
4587 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4588 pSMB->TotalDataCount = 0;
4589 pSMB->MaxParameterCount = cpu_to_le16(2);
4590 /* BB find exact max data count below from sess structure BB */
4591 pSMB->MaxDataCount = cpu_to_le16(4000);
4592 pSMB->MaxSetupCount = 0;
4593 pSMB->Reserved = 0;
4594 pSMB->Flags = 0;
4595 pSMB->Timeout = 0;
4596 pSMB->Reserved2 = 0;
4597 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004598 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004599 pSMB->DataCount = 0;
4600 pSMB->DataOffset = 0;
4601 pSMB->SetupCount = 1;
4602 pSMB->Reserved3 = 0;
4603 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4604 byte_count = params + 1 /* pad */ ;
4605 pSMB->TotalParameterCount = cpu_to_le16(params);
4606 pSMB->ParameterCount = pSMB->TotalParameterCount;
4607 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4608 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004609 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004610 pSMB->ByteCount = cpu_to_le16(byte_count);
4611
4612 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4613 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4614 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004615 cFYI(1, "error %d in QueryInternalInfo", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004616 } else {
4617 /* decode response */
4618 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004619 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04004620 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004621 /* If rc should we check for EOPNOSUPP and
4622 disable the srvino flag? or in caller? */
4623 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00004624 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004625 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4626 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00004627 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004628 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00004629 if (count < 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004630 cFYI(1, "Illegal size ret in QryIntrnlInf");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004631 rc = -EIO;
4632 goto GetInodeNumOut;
4633 }
4634 pfinfo = (struct file_internal_info *)
4635 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00004636 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004637 }
4638 }
4639GetInodeNumOut:
4640 cifs_buf_release(pSMB);
4641 if (rc == -EAGAIN)
4642 goto GetInodeNumberRetry;
4643 return rc;
4644}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004645
Igor Mammedovfec45852008-05-16 13:06:30 +04004646/* parses DFS refferal V3 structure
4647 * caller is responsible for freeing target_nodes
4648 * returns:
4649 * on success - 0
4650 * on failure - errno
4651 */
4652static int
Steve Frencha1fe78f2008-05-16 18:48:38 +00004653parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
Igor Mammedovfec45852008-05-16 13:06:30 +04004654 unsigned int *num_of_nodes,
4655 struct dfs_info3_param **target_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004656 const struct nls_table *nls_codepage, int remap,
4657 const char *searchName)
Igor Mammedovfec45852008-05-16 13:06:30 +04004658{
4659 int i, rc = 0;
4660 char *data_end;
4661 bool is_unicode;
4662 struct dfs_referral_level_3 *ref;
4663
Harvey Harrison5ca33c62008-07-23 17:45:58 -07004664 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4665 is_unicode = true;
4666 else
4667 is_unicode = false;
Igor Mammedovfec45852008-05-16 13:06:30 +04004668 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
4669
4670 if (*num_of_nodes < 1) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004671 cERROR(1, "num_referrals: must be at least > 0,"
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004672 "but we get num_referrals = %d", *num_of_nodes);
Igor Mammedovfec45852008-05-16 13:06:30 +04004673 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004674 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004675 }
4676
4677 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
Al Viro1d92cfd2008-06-02 10:59:02 +01004678 if (ref->VersionNumber != cpu_to_le16(3)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004679 cERROR(1, "Referrals of V%d version are not supported,"
4680 "should be V3", le16_to_cpu(ref->VersionNumber));
Igor Mammedovfec45852008-05-16 13:06:30 +04004681 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004682 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004683 }
4684
4685 /* get the upper boundary of the resp buffer */
4686 data_end = (char *)(&(pSMBr->PathConsumed)) +
4687 le16_to_cpu(pSMBr->t2.DataCount);
4688
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004689 cFYI(1, "num_referrals: %d dfs flags: 0x%x ...",
Igor Mammedovfec45852008-05-16 13:06:30 +04004690 *num_of_nodes,
Joe Perchesb6b38f72010-04-21 03:50:45 +00004691 le32_to_cpu(pSMBr->DFSFlags));
Igor Mammedovfec45852008-05-16 13:06:30 +04004692
4693 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
4694 *num_of_nodes, GFP_KERNEL);
4695 if (*target_nodes == NULL) {
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004696 cERROR(1, "Failed to allocate buffer for target_nodes");
Igor Mammedovfec45852008-05-16 13:06:30 +04004697 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004698 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004699 }
4700
Daniel Mack3ad2f3f2010-02-03 08:01:28 +08004701 /* collect necessary data from referrals */
Igor Mammedovfec45852008-05-16 13:06:30 +04004702 for (i = 0; i < *num_of_nodes; i++) {
4703 char *temp;
4704 int max_len;
4705 struct dfs_info3_param *node = (*target_nodes)+i;
4706
Steve French0e0d2cf2009-05-01 05:27:32 +00004707 node->flags = le32_to_cpu(pSMBr->DFSFlags);
Igor Mammedov2c556082008-10-23 13:58:42 +04004708 if (is_unicode) {
Jeff Layton331c3132008-12-17 06:31:53 -05004709 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4710 GFP_KERNEL);
Steve French2920ee22009-08-31 15:27:26 +00004711 if (tmp == NULL) {
4712 rc = -ENOMEM;
4713 goto parse_DFS_referrals_exit;
4714 }
Steve Frenchacbbb762012-01-18 22:32:33 -06004715 cifsConvertToUTF16((__le16 *) tmp, searchName,
4716 PATH_MAX, nls_codepage, remap);
4717 node->path_consumed = cifs_utf16_bytes(tmp,
Jeff Layton69f801f2009-04-30 06:46:32 -04004718 le16_to_cpu(pSMBr->PathConsumed),
Igor Mammedov2c556082008-10-23 13:58:42 +04004719 nls_codepage);
4720 kfree(tmp);
4721 } else
4722 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4723
Igor Mammedovfec45852008-05-16 13:06:30 +04004724 node->server_type = le16_to_cpu(ref->ServerType);
4725 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4726
4727 /* copy DfsPath */
4728 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4729 max_len = data_end - temp;
Steve Frenchacbbb762012-01-18 22:32:33 -06004730 node->path_name = cifs_strndup_from_utf16(temp, max_len,
4731 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004732 if (!node->path_name) {
4733 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004734 goto parse_DFS_referrals_exit;
Jeff Layton066ce682009-04-30 07:16:14 -04004735 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004736
4737 /* copy link target UNC */
4738 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4739 max_len = data_end - temp;
Steve Frenchacbbb762012-01-18 22:32:33 -06004740 node->node_name = cifs_strndup_from_utf16(temp, max_len,
4741 is_unicode, nls_codepage);
Stefan Metzmacherd8f27992012-05-04 00:19:28 +02004742 if (!node->node_name) {
Jeff Laytond8e2f532009-05-14 07:46:59 -04004743 rc = -ENOMEM;
Stefan Metzmacherd8f27992012-05-04 00:19:28 +02004744 goto parse_DFS_referrals_exit;
4745 }
4746
4747 ref++;
Igor Mammedovfec45852008-05-16 13:06:30 +04004748 }
4749
Steve Frencha1fe78f2008-05-16 18:48:38 +00004750parse_DFS_referrals_exit:
Igor Mammedovfec45852008-05-16 13:06:30 +04004751 if (rc) {
4752 free_dfs_info_array(*target_nodes, *num_of_nodes);
4753 *target_nodes = NULL;
4754 *num_of_nodes = 0;
4755 }
4756 return rc;
4757}
4758
Linus Torvalds1da177e2005-04-16 15:20:36 -07004759int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004760CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004761 const char *search_name, struct dfs_info3_param **target_nodes,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004762 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004763 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004764{
4765/* TRANS2_GET_DFS_REFERRAL */
4766 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4767 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004768 int rc = 0;
4769 int bytes_returned;
4770 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004771 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004772 *num_of_nodes = 0;
4773 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004774
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004775 cFYI(1, "In GetDFSRefer the path %s", search_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004776 if (ses == NULL)
4777 return -ENODEV;
4778getDFSRetry:
4779 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4780 (void **) &pSMBr);
4781 if (rc)
4782 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004783
4784 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004785 but should never be null here anyway */
Pavel Shilovsky88257362012-05-23 14:01:59 +04004786 pSMB->hdr.Mid = get_next_mid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004787 pSMB->hdr.Tid = ses->ipc_tid;
4788 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004789 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004790 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004791 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004792 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004793
4794 if (ses->capabilities & CAP_UNICODE) {
4795 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4796 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004797 cifsConvertToUTF16((__le16 *) pSMB->RequestFileName,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004798 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004799 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004800 name_len++; /* trailing null */
4801 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004802 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004803 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004804 name_len++; /* trailing null */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004805 strncpy(pSMB->RequestFileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004806 }
4807
Steve French790fe572007-07-07 19:25:05 +00004808 if (ses->server) {
Steve French96daf2b2011-05-27 04:34:02 +00004809 if (ses->server->sec_mode &
Steve French1a4e15a2006-10-12 21:33:51 +00004810 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4811 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4812 }
4813
Steve French50c2f752007-07-13 00:33:32 +00004814 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004815
Linus Torvalds1da177e2005-04-16 15:20:36 -07004816 params = 2 /* level */ + name_len /*includes null */ ;
4817 pSMB->TotalDataCount = 0;
4818 pSMB->DataCount = 0;
4819 pSMB->DataOffset = 0;
4820 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004821 /* BB find exact max SMB PDU from sess structure BB */
4822 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004823 pSMB->MaxSetupCount = 0;
4824 pSMB->Reserved = 0;
4825 pSMB->Flags = 0;
4826 pSMB->Timeout = 0;
4827 pSMB->Reserved2 = 0;
4828 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004829 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004830 pSMB->SetupCount = 1;
4831 pSMB->Reserved3 = 0;
4832 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4833 byte_count = params + 3 /* pad */ ;
4834 pSMB->ParameterCount = cpu_to_le16(params);
4835 pSMB->TotalParameterCount = pSMB->ParameterCount;
4836 pSMB->MaxReferralLevel = cpu_to_le16(3);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004837 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004838 pSMB->ByteCount = cpu_to_le16(byte_count);
4839
4840 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4841 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4842 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004843 cFYI(1, "Send error in GetDFSRefer = %d", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004844 goto GetDFSRefExit;
4845 }
4846 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004847
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004848 /* BB Also check if enough total bytes returned? */
Jeff Layton820a8032011-05-04 08:05:26 -04004849 if (rc || get_bcc(&pSMBr->hdr) < 17) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004850 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004851 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004852 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004853
Joe Perchesb6b38f72010-04-21 03:50:45 +00004854 cFYI(1, "Decoding GetDFSRefer response BCC: %d Offset %d",
Jeff Layton820a8032011-05-04 08:05:26 -04004855 get_bcc(&pSMBr->hdr),
Joe Perchesb6b38f72010-04-21 03:50:45 +00004856 le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04004857
4858 /* parse returned result into more usable form */
Steve Frencha1fe78f2008-05-16 18:48:38 +00004859 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004860 target_nodes, nls_codepage, remap,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004861 search_name);
Igor Mammedovfec45852008-05-16 13:06:30 +04004862
Linus Torvalds1da177e2005-04-16 15:20:36 -07004863GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004864 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004865
4866 if (rc == -EAGAIN)
4867 goto getDFSRetry;
4868
4869 return rc;
4870}
4871
Steve French20962432005-09-21 22:05:57 -07004872/* Query File System Info such as free space to old servers such as Win 9x */
4873int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004874SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4875 struct kstatfs *FSData)
Steve French20962432005-09-21 22:05:57 -07004876{
4877/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4878 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4879 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4880 FILE_SYSTEM_ALLOC_INFO *response_data;
4881 int rc = 0;
4882 int bytes_returned = 0;
4883 __u16 params, byte_count;
4884
Joe Perchesb6b38f72010-04-21 03:50:45 +00004885 cFYI(1, "OldQFSInfo");
Steve French20962432005-09-21 22:05:57 -07004886oldQFSInfoRetry:
4887 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4888 (void **) &pSMBr);
4889 if (rc)
4890 return rc;
Steve French20962432005-09-21 22:05:57 -07004891
4892 params = 2; /* level */
4893 pSMB->TotalDataCount = 0;
4894 pSMB->MaxParameterCount = cpu_to_le16(2);
4895 pSMB->MaxDataCount = cpu_to_le16(1000);
4896 pSMB->MaxSetupCount = 0;
4897 pSMB->Reserved = 0;
4898 pSMB->Flags = 0;
4899 pSMB->Timeout = 0;
4900 pSMB->Reserved2 = 0;
4901 byte_count = params + 1 /* pad */ ;
4902 pSMB->TotalParameterCount = cpu_to_le16(params);
4903 pSMB->ParameterCount = pSMB->TotalParameterCount;
4904 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4905 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4906 pSMB->DataCount = 0;
4907 pSMB->DataOffset = 0;
4908 pSMB->SetupCount = 1;
4909 pSMB->Reserved3 = 0;
4910 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4911 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004912 inc_rfc1001_len(pSMB, byte_count);
Steve French20962432005-09-21 22:05:57 -07004913 pSMB->ByteCount = cpu_to_le16(byte_count);
4914
4915 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4916 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4917 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004918 cFYI(1, "Send error in QFSInfo = %d", rc);
Steve French20962432005-09-21 22:05:57 -07004919 } else { /* decode response */
4920 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4921
Jeff Layton820a8032011-05-04 08:05:26 -04004922 if (rc || get_bcc(&pSMBr->hdr) < 18)
Steve French20962432005-09-21 22:05:57 -07004923 rc = -EIO; /* bad smb */
4924 else {
4925 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004926 cFYI(1, "qfsinf resp BCC: %d Offset %d",
Jeff Layton820a8032011-05-04 08:05:26 -04004927 get_bcc(&pSMBr->hdr), data_offset);
Steve French20962432005-09-21 22:05:57 -07004928
Steve French50c2f752007-07-13 00:33:32 +00004929 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004930 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4931 FSData->f_bsize =
4932 le16_to_cpu(response_data->BytesPerSector) *
4933 le32_to_cpu(response_data->
4934 SectorsPerAllocationUnit);
4935 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004936 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004937 FSData->f_bfree = FSData->f_bavail =
4938 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004939 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
4940 (unsigned long long)FSData->f_blocks,
4941 (unsigned long long)FSData->f_bfree,
4942 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07004943 }
4944 }
4945 cifs_buf_release(pSMB);
4946
4947 if (rc == -EAGAIN)
4948 goto oldQFSInfoRetry;
4949
4950 return rc;
4951}
4952
Linus Torvalds1da177e2005-04-16 15:20:36 -07004953int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004954CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4955 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004956{
4957/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4958 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4959 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4960 FILE_SYSTEM_INFO *response_data;
4961 int rc = 0;
4962 int bytes_returned = 0;
4963 __u16 params, byte_count;
4964
Joe Perchesb6b38f72010-04-21 03:50:45 +00004965 cFYI(1, "In QFSInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004966QFSInfoRetry:
4967 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4968 (void **) &pSMBr);
4969 if (rc)
4970 return rc;
4971
4972 params = 2; /* level */
4973 pSMB->TotalDataCount = 0;
4974 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004975 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004976 pSMB->MaxSetupCount = 0;
4977 pSMB->Reserved = 0;
4978 pSMB->Flags = 0;
4979 pSMB->Timeout = 0;
4980 pSMB->Reserved2 = 0;
4981 byte_count = params + 1 /* pad */ ;
4982 pSMB->TotalParameterCount = cpu_to_le16(params);
4983 pSMB->ParameterCount = pSMB->TotalParameterCount;
4984 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004985 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004986 pSMB->DataCount = 0;
4987 pSMB->DataOffset = 0;
4988 pSMB->SetupCount = 1;
4989 pSMB->Reserved3 = 0;
4990 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4991 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004992 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004993 pSMB->ByteCount = cpu_to_le16(byte_count);
4994
4995 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4996 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4997 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004998 cFYI(1, "Send error in QFSInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004999 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00005000 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005001
Jeff Layton820a8032011-05-04 08:05:26 -04005002 if (rc || get_bcc(&pSMBr->hdr) < 24)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005003 rc = -EIO; /* bad smb */
5004 else {
5005 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005006
5007 response_data =
5008 (FILE_SYSTEM_INFO
5009 *) (((char *) &pSMBr->hdr.Protocol) +
5010 data_offset);
5011 FSData->f_bsize =
5012 le32_to_cpu(response_data->BytesPerSector) *
5013 le32_to_cpu(response_data->
5014 SectorsPerAllocationUnit);
5015 FSData->f_blocks =
5016 le64_to_cpu(response_data->TotalAllocationUnits);
5017 FSData->f_bfree = FSData->f_bavail =
5018 le64_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesb6b38f72010-04-21 03:50:45 +00005019 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
5020 (unsigned long long)FSData->f_blocks,
5021 (unsigned long long)FSData->f_bfree,
5022 FSData->f_bsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005023 }
5024 }
5025 cifs_buf_release(pSMB);
5026
5027 if (rc == -EAGAIN)
5028 goto QFSInfoRetry;
5029
5030 return rc;
5031}
5032
5033int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005034CIFSSMBQFSAttributeInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005035{
5036/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
5037 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5038 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5039 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
5040 int rc = 0;
5041 int bytes_returned = 0;
5042 __u16 params, byte_count;
5043
Joe Perchesb6b38f72010-04-21 03:50:45 +00005044 cFYI(1, "In QFSAttributeInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005045QFSAttributeRetry:
5046 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5047 (void **) &pSMBr);
5048 if (rc)
5049 return rc;
5050
5051 params = 2; /* level */
5052 pSMB->TotalDataCount = 0;
5053 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005054 /* BB find exact max SMB PDU from sess structure BB */
5055 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005056 pSMB->MaxSetupCount = 0;
5057 pSMB->Reserved = 0;
5058 pSMB->Flags = 0;
5059 pSMB->Timeout = 0;
5060 pSMB->Reserved2 = 0;
5061 byte_count = params + 1 /* pad */ ;
5062 pSMB->TotalParameterCount = cpu_to_le16(params);
5063 pSMB->ParameterCount = pSMB->TotalParameterCount;
5064 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005065 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005066 pSMB->DataCount = 0;
5067 pSMB->DataOffset = 0;
5068 pSMB->SetupCount = 1;
5069 pSMB->Reserved3 = 0;
5070 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5071 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005072 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005073 pSMB->ByteCount = cpu_to_le16(byte_count);
5074
5075 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5076 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5077 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005078 cERROR(1, "Send error in QFSAttributeInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005079 } else { /* decode response */
5080 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5081
Jeff Layton820a8032011-05-04 08:05:26 -04005082 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Steve French50c2f752007-07-13 00:33:32 +00005083 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005084 rc = -EIO; /* bad smb */
5085 } else {
5086 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5087 response_data =
5088 (FILE_SYSTEM_ATTRIBUTE_INFO
5089 *) (((char *) &pSMBr->hdr.Protocol) +
5090 data_offset);
5091 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005092 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005093 }
5094 }
5095 cifs_buf_release(pSMB);
5096
5097 if (rc == -EAGAIN)
5098 goto QFSAttributeRetry;
5099
5100 return rc;
5101}
5102
5103int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005104CIFSSMBQFSDeviceInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005105{
5106/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
5107 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5108 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5109 FILE_SYSTEM_DEVICE_INFO *response_data;
5110 int rc = 0;
5111 int bytes_returned = 0;
5112 __u16 params, byte_count;
5113
Joe Perchesb6b38f72010-04-21 03:50:45 +00005114 cFYI(1, "In QFSDeviceInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005115QFSDeviceRetry:
5116 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5117 (void **) &pSMBr);
5118 if (rc)
5119 return rc;
5120
5121 params = 2; /* level */
5122 pSMB->TotalDataCount = 0;
5123 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005124 /* BB find exact max SMB PDU from sess structure BB */
5125 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005126 pSMB->MaxSetupCount = 0;
5127 pSMB->Reserved = 0;
5128 pSMB->Flags = 0;
5129 pSMB->Timeout = 0;
5130 pSMB->Reserved2 = 0;
5131 byte_count = params + 1 /* pad */ ;
5132 pSMB->TotalParameterCount = cpu_to_le16(params);
5133 pSMB->ParameterCount = pSMB->TotalParameterCount;
5134 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005135 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005136
5137 pSMB->DataCount = 0;
5138 pSMB->DataOffset = 0;
5139 pSMB->SetupCount = 1;
5140 pSMB->Reserved3 = 0;
5141 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5142 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005143 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005144 pSMB->ByteCount = cpu_to_le16(byte_count);
5145
5146 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5147 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5148 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005149 cFYI(1, "Send error in QFSDeviceInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005150 } else { /* decode response */
5151 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5152
Jeff Layton820a8032011-05-04 08:05:26 -04005153 if (rc || get_bcc(&pSMBr->hdr) <
5154 sizeof(FILE_SYSTEM_DEVICE_INFO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005155 rc = -EIO; /* bad smb */
5156 else {
5157 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5158 response_data =
Steve French737b7582005-04-28 22:41:06 -07005159 (FILE_SYSTEM_DEVICE_INFO *)
5160 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07005161 data_offset);
5162 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005163 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005164 }
5165 }
5166 cifs_buf_release(pSMB);
5167
5168 if (rc == -EAGAIN)
5169 goto QFSDeviceRetry;
5170
5171 return rc;
5172}
5173
5174int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005175CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005176{
5177/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
5178 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5179 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5180 FILE_SYSTEM_UNIX_INFO *response_data;
5181 int rc = 0;
5182 int bytes_returned = 0;
5183 __u16 params, byte_count;
5184
Joe Perchesb6b38f72010-04-21 03:50:45 +00005185 cFYI(1, "In QFSUnixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005186QFSUnixRetry:
Jeff Laytonf5695992010-09-29 15:27:08 -04005187 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5188 (void **) &pSMB, (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005189 if (rc)
5190 return rc;
5191
5192 params = 2; /* level */
5193 pSMB->TotalDataCount = 0;
5194 pSMB->DataCount = 0;
5195 pSMB->DataOffset = 0;
5196 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005197 /* BB find exact max SMB PDU from sess structure BB */
5198 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005199 pSMB->MaxSetupCount = 0;
5200 pSMB->Reserved = 0;
5201 pSMB->Flags = 0;
5202 pSMB->Timeout = 0;
5203 pSMB->Reserved2 = 0;
5204 byte_count = params + 1 /* pad */ ;
5205 pSMB->ParameterCount = cpu_to_le16(params);
5206 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005207 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5208 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005209 pSMB->SetupCount = 1;
5210 pSMB->Reserved3 = 0;
5211 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5212 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005213 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005214 pSMB->ByteCount = cpu_to_le16(byte_count);
5215
5216 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5217 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5218 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005219 cERROR(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005220 } else { /* decode response */
5221 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5222
Jeff Layton820a8032011-05-04 08:05:26 -04005223 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005224 rc = -EIO; /* bad smb */
5225 } else {
5226 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5227 response_data =
5228 (FILE_SYSTEM_UNIX_INFO
5229 *) (((char *) &pSMBr->hdr.Protocol) +
5230 data_offset);
5231 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005232 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005233 }
5234 }
5235 cifs_buf_release(pSMB);
5236
5237 if (rc == -EAGAIN)
5238 goto QFSUnixRetry;
5239
5240
5241 return rc;
5242}
5243
Jeremy Allisonac670552005-06-22 17:26:35 -07005244int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005245CIFSSMBSetFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07005246{
5247/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
5248 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
5249 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
5250 int rc = 0;
5251 int bytes_returned = 0;
5252 __u16 params, param_offset, offset, byte_count;
5253
Joe Perchesb6b38f72010-04-21 03:50:45 +00005254 cFYI(1, "In SETFSUnixInfo");
Jeremy Allisonac670552005-06-22 17:26:35 -07005255SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00005256 /* BB switch to small buf init to save memory */
Jeff Laytonf5695992010-09-29 15:27:08 -04005257 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5258 (void **) &pSMB, (void **) &pSMBr);
Jeremy Allisonac670552005-06-22 17:26:35 -07005259 if (rc)
5260 return rc;
5261
5262 params = 4; /* 2 bytes zero followed by info level. */
5263 pSMB->MaxSetupCount = 0;
5264 pSMB->Reserved = 0;
5265 pSMB->Flags = 0;
5266 pSMB->Timeout = 0;
5267 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00005268 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
5269 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07005270 offset = param_offset + params;
5271
5272 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00005273 /* BB find exact max SMB PDU from sess structure BB */
5274 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07005275 pSMB->SetupCount = 1;
5276 pSMB->Reserved3 = 0;
5277 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
5278 byte_count = 1 /* pad */ + params + 12;
5279
5280 pSMB->DataCount = cpu_to_le16(12);
5281 pSMB->ParameterCount = cpu_to_le16(params);
5282 pSMB->TotalDataCount = pSMB->DataCount;
5283 pSMB->TotalParameterCount = pSMB->ParameterCount;
5284 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5285 pSMB->DataOffset = cpu_to_le16(offset);
5286
5287 /* Params. */
5288 pSMB->FileNum = 0;
5289 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
5290
5291 /* Data. */
5292 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
5293 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
5294 pSMB->ClientUnixCap = cpu_to_le64(cap);
5295
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005296 inc_rfc1001_len(pSMB, byte_count);
Jeremy Allisonac670552005-06-22 17:26:35 -07005297 pSMB->ByteCount = cpu_to_le16(byte_count);
5298
5299 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5300 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5301 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005302 cERROR(1, "Send error in SETFSUnixInfo = %d", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07005303 } else { /* decode response */
5304 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00005305 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07005306 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07005307 }
5308 cifs_buf_release(pSMB);
5309
5310 if (rc == -EAGAIN)
5311 goto SETFSUnixRetry;
5312
5313 return rc;
5314}
5315
5316
Linus Torvalds1da177e2005-04-16 15:20:36 -07005317
5318int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005319CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon,
Steve French737b7582005-04-28 22:41:06 -07005320 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005321{
5322/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
5323 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5324 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5325 FILE_SYSTEM_POSIX_INFO *response_data;
5326 int rc = 0;
5327 int bytes_returned = 0;
5328 __u16 params, byte_count;
5329
Joe Perchesb6b38f72010-04-21 03:50:45 +00005330 cFYI(1, "In QFSPosixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005331QFSPosixRetry:
5332 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5333 (void **) &pSMBr);
5334 if (rc)
5335 return rc;
5336
5337 params = 2; /* level */
5338 pSMB->TotalDataCount = 0;
5339 pSMB->DataCount = 0;
5340 pSMB->DataOffset = 0;
5341 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005342 /* BB find exact max SMB PDU from sess structure BB */
5343 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005344 pSMB->MaxSetupCount = 0;
5345 pSMB->Reserved = 0;
5346 pSMB->Flags = 0;
5347 pSMB->Timeout = 0;
5348 pSMB->Reserved2 = 0;
5349 byte_count = params + 1 /* pad */ ;
5350 pSMB->ParameterCount = cpu_to_le16(params);
5351 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005352 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5353 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005354 pSMB->SetupCount = 1;
5355 pSMB->Reserved3 = 0;
5356 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5357 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005358 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005359 pSMB->ByteCount = cpu_to_le16(byte_count);
5360
5361 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5362 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5363 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005364 cFYI(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005365 } else { /* decode response */
5366 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5367
Jeff Layton820a8032011-05-04 08:05:26 -04005368 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005369 rc = -EIO; /* bad smb */
5370 } else {
5371 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5372 response_data =
5373 (FILE_SYSTEM_POSIX_INFO
5374 *) (((char *) &pSMBr->hdr.Protocol) +
5375 data_offset);
5376 FSData->f_bsize =
5377 le32_to_cpu(response_data->BlockSize);
5378 FSData->f_blocks =
5379 le64_to_cpu(response_data->TotalBlocks);
5380 FSData->f_bfree =
5381 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00005382 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005383 FSData->f_bavail = FSData->f_bfree;
5384 } else {
5385 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00005386 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005387 }
Steve French790fe572007-07-07 19:25:05 +00005388 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005389 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00005390 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00005391 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005392 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00005393 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005394 }
5395 }
5396 cifs_buf_release(pSMB);
5397
5398 if (rc == -EAGAIN)
5399 goto QFSPosixRetry;
5400
5401 return rc;
5402}
5403
5404
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005405/*
5406 * We can not use write of zero bytes trick to set file size due to need for
5407 * large file support. Also note that this SetPathInfo is preferred to
5408 * SetFileInfo based method in next routine which is only needed to work around
5409 * a sharing violation bugin Samba which this routine can run into.
5410 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005411int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005412CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005413 const char *file_name, __u64 size, struct cifs_sb_info *cifs_sb,
5414 bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005415{
5416 struct smb_com_transaction2_spi_req *pSMB = NULL;
5417 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5418 struct file_end_of_file_info *parm_data;
5419 int name_len;
5420 int rc = 0;
5421 int bytes_returned = 0;
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005422 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
5423
Linus Torvalds1da177e2005-04-16 15:20:36 -07005424 __u16 params, byte_count, data_count, param_offset, offset;
5425
Joe Perchesb6b38f72010-04-21 03:50:45 +00005426 cFYI(1, "In SetEOF");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005427SetEOFRetry:
5428 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5429 (void **) &pSMBr);
5430 if (rc)
5431 return rc;
5432
5433 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5434 name_len =
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005435 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
5436 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005437 name_len++; /* trailing null */
5438 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005439 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005440 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005441 name_len++; /* trailing null */
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005442 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005443 }
5444 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005445 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005446 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07005447 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005448 pSMB->MaxSetupCount = 0;
5449 pSMB->Reserved = 0;
5450 pSMB->Flags = 0;
5451 pSMB->Timeout = 0;
5452 pSMB->Reserved2 = 0;
5453 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005454 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005455 offset = param_offset + params;
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005456 if (set_allocation) {
Steve French50c2f752007-07-13 00:33:32 +00005457 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5458 pSMB->InformationLevel =
5459 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5460 else
5461 pSMB->InformationLevel =
5462 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5463 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005464 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5465 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005466 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005467 else
5468 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005469 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005470 }
5471
5472 parm_data =
5473 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
5474 offset);
5475 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5476 pSMB->DataOffset = cpu_to_le16(offset);
5477 pSMB->SetupCount = 1;
5478 pSMB->Reserved3 = 0;
5479 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5480 byte_count = 3 /* pad */ + params + data_count;
5481 pSMB->DataCount = cpu_to_le16(data_count);
5482 pSMB->TotalDataCount = pSMB->DataCount;
5483 pSMB->ParameterCount = cpu_to_le16(params);
5484 pSMB->TotalParameterCount = pSMB->ParameterCount;
5485 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005486 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005487 parm_data->FileSize = cpu_to_le64(size);
5488 pSMB->ByteCount = cpu_to_le16(byte_count);
5489 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5490 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005491 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005492 cFYI(1, "SetPathInfo (file size) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005493
5494 cifs_buf_release(pSMB);
5495
5496 if (rc == -EAGAIN)
5497 goto SetEOFRetry;
5498
5499 return rc;
5500}
5501
5502int
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005503CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
5504 struct cifsFileInfo *cfile, __u64 size, bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005505{
5506 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005507 struct file_end_of_file_info *parm_data;
5508 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005509 __u16 params, param_offset, offset, byte_count, count;
5510
Joe Perchesb6b38f72010-04-21 03:50:45 +00005511 cFYI(1, "SetFileSize (via SetFileInfo) %lld",
5512 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07005513 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5514
Linus Torvalds1da177e2005-04-16 15:20:36 -07005515 if (rc)
5516 return rc;
5517
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005518 pSMB->hdr.Pid = cpu_to_le16((__u16)cfile->pid);
5519 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(cfile->pid >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005520
Linus Torvalds1da177e2005-04-16 15:20:36 -07005521 params = 6;
5522 pSMB->MaxSetupCount = 0;
5523 pSMB->Reserved = 0;
5524 pSMB->Flags = 0;
5525 pSMB->Timeout = 0;
5526 pSMB->Reserved2 = 0;
5527 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5528 offset = param_offset + params;
5529
Linus Torvalds1da177e2005-04-16 15:20:36 -07005530 count = sizeof(struct file_end_of_file_info);
5531 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005532 /* BB find exact max SMB PDU from sess structure BB */
5533 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005534 pSMB->SetupCount = 1;
5535 pSMB->Reserved3 = 0;
5536 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5537 byte_count = 3 /* pad */ + params + count;
5538 pSMB->DataCount = cpu_to_le16(count);
5539 pSMB->ParameterCount = cpu_to_le16(params);
5540 pSMB->TotalDataCount = pSMB->DataCount;
5541 pSMB->TotalParameterCount = pSMB->ParameterCount;
5542 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5543 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00005544 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
5545 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005546 pSMB->DataOffset = cpu_to_le16(offset);
5547 parm_data->FileSize = cpu_to_le64(size);
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005548 pSMB->Fid = cfile->fid.netfid;
5549 if (set_allocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005550 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5551 pSMB->InformationLevel =
5552 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5553 else
5554 pSMB->InformationLevel =
5555 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00005556 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005557 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5558 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005559 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005560 else
5561 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005562 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005563 }
5564 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005565 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005566 pSMB->ByteCount = cpu_to_le16(byte_count);
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005567 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005568 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005569 cFYI(1, "Send error in SetFileInfo (SetFileSize) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005570 }
5571
Steve French50c2f752007-07-13 00:33:32 +00005572 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005573 since file handle passed in no longer valid */
5574
5575 return rc;
5576}
5577
Steve French50c2f752007-07-13 00:33:32 +00005578/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07005579 an open handle, rather than by pathname - this is awkward due to
5580 potential access conflicts on the open, but it is unavoidable for these
5581 old servers since the only other choice is to go from 100 nanosecond DCE
5582 time and resort to the original setpathinfo level which takes the ancient
5583 DOS time format with 2 second granularity */
5584int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005585CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005586 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005587{
5588 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005589 char *data_offset;
5590 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005591 __u16 params, param_offset, offset, byte_count, count;
5592
Joe Perchesb6b38f72010-04-21 03:50:45 +00005593 cFYI(1, "Set Times (via SetFileInfo)");
Steve Frenchcd634992005-04-28 22:41:10 -07005594 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5595
Linus Torvalds1da177e2005-04-16 15:20:36 -07005596 if (rc)
5597 return rc;
5598
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005599 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5600 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005601
Linus Torvalds1da177e2005-04-16 15:20:36 -07005602 params = 6;
5603 pSMB->MaxSetupCount = 0;
5604 pSMB->Reserved = 0;
5605 pSMB->Flags = 0;
5606 pSMB->Timeout = 0;
5607 pSMB->Reserved2 = 0;
5608 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5609 offset = param_offset + params;
5610
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005611 data_offset = (char *)pSMB +
5612 offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005613
Steve French26f57362007-08-30 22:09:15 +00005614 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005615 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005616 /* BB find max SMB PDU from sess */
5617 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005618 pSMB->SetupCount = 1;
5619 pSMB->Reserved3 = 0;
5620 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5621 byte_count = 3 /* pad */ + params + count;
5622 pSMB->DataCount = cpu_to_le16(count);
5623 pSMB->ParameterCount = cpu_to_le16(params);
5624 pSMB->TotalDataCount = pSMB->DataCount;
5625 pSMB->TotalParameterCount = pSMB->ParameterCount;
5626 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5627 pSMB->DataOffset = cpu_to_le16(offset);
5628 pSMB->Fid = fid;
5629 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5630 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5631 else
5632 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5633 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005634 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005635 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005636 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005637 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005638 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005639 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005640
Steve French50c2f752007-07-13 00:33:32 +00005641 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005642 since file handle passed in no longer valid */
5643
5644 return rc;
5645}
5646
Jeff Layton6d22f092008-09-23 11:48:35 -04005647int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005648CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6d22f092008-09-23 11:48:35 -04005649 bool delete_file, __u16 fid, __u32 pid_of_opener)
5650{
5651 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5652 char *data_offset;
5653 int rc = 0;
5654 __u16 params, param_offset, offset, byte_count, count;
5655
Joe Perchesb6b38f72010-04-21 03:50:45 +00005656 cFYI(1, "Set File Disposition (via SetFileInfo)");
Jeff Layton6d22f092008-09-23 11:48:35 -04005657 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5658
5659 if (rc)
5660 return rc;
5661
5662 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5663 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5664
5665 params = 6;
5666 pSMB->MaxSetupCount = 0;
5667 pSMB->Reserved = 0;
5668 pSMB->Flags = 0;
5669 pSMB->Timeout = 0;
5670 pSMB->Reserved2 = 0;
5671 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5672 offset = param_offset + params;
5673
5674 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5675
5676 count = 1;
5677 pSMB->MaxParameterCount = cpu_to_le16(2);
5678 /* BB find max SMB PDU from sess */
5679 pSMB->MaxDataCount = cpu_to_le16(1000);
5680 pSMB->SetupCount = 1;
5681 pSMB->Reserved3 = 0;
5682 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5683 byte_count = 3 /* pad */ + params + count;
5684 pSMB->DataCount = cpu_to_le16(count);
5685 pSMB->ParameterCount = cpu_to_le16(params);
5686 pSMB->TotalDataCount = pSMB->DataCount;
5687 pSMB->TotalParameterCount = pSMB->ParameterCount;
5688 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5689 pSMB->DataOffset = cpu_to_le16(offset);
5690 pSMB->Fid = fid;
5691 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5692 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005693 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton6d22f092008-09-23 11:48:35 -04005694 pSMB->ByteCount = cpu_to_le16(byte_count);
5695 *data_offset = delete_file ? 1 : 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005696 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Jeff Layton6d22f092008-09-23 11:48:35 -04005697 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005698 cFYI(1, "Send error in SetFileDisposition = %d", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005699
5700 return rc;
5701}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005702
5703int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005704CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6fc000e2008-08-02 07:26:12 -04005705 const char *fileName, const FILE_BASIC_INFO *data,
5706 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005707{
5708 TRANSACTION2_SPI_REQ *pSMB = NULL;
5709 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5710 int name_len;
5711 int rc = 0;
5712 int bytes_returned = 0;
5713 char *data_offset;
5714 __u16 params, param_offset, offset, byte_count, count;
5715
Joe Perchesb6b38f72010-04-21 03:50:45 +00005716 cFYI(1, "In SetTimes");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005717
5718SetTimesRetry:
5719 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5720 (void **) &pSMBr);
5721 if (rc)
5722 return rc;
5723
5724 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5725 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005726 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5727 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005728 name_len++; /* trailing null */
5729 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005730 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005731 name_len = strnlen(fileName, PATH_MAX);
5732 name_len++; /* trailing null */
5733 strncpy(pSMB->FileName, fileName, name_len);
5734 }
5735
5736 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005737 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005738 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005739 /* BB find max SMB PDU from sess structure BB */
5740 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005741 pSMB->MaxSetupCount = 0;
5742 pSMB->Reserved = 0;
5743 pSMB->Flags = 0;
5744 pSMB->Timeout = 0;
5745 pSMB->Reserved2 = 0;
5746 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005747 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005748 offset = param_offset + params;
5749 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5750 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5751 pSMB->DataOffset = cpu_to_le16(offset);
5752 pSMB->SetupCount = 1;
5753 pSMB->Reserved3 = 0;
5754 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5755 byte_count = 3 /* pad */ + params + count;
5756
5757 pSMB->DataCount = cpu_to_le16(count);
5758 pSMB->ParameterCount = cpu_to_le16(params);
5759 pSMB->TotalDataCount = pSMB->DataCount;
5760 pSMB->TotalParameterCount = pSMB->ParameterCount;
5761 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5762 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5763 else
5764 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5765 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005766 inc_rfc1001_len(pSMB, byte_count);
Steve French26f57362007-08-30 22:09:15 +00005767 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005768 pSMB->ByteCount = cpu_to_le16(byte_count);
5769 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5770 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005771 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005772 cFYI(1, "SetPathInfo (times) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005773
5774 cifs_buf_release(pSMB);
5775
5776 if (rc == -EAGAIN)
5777 goto SetTimesRetry;
5778
5779 return rc;
5780}
5781
5782/* Can not be used to set time stamps yet (due to old DOS time format) */
5783/* Can be used to set attributes */
5784#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5785 handling it anyway and NT4 was what we thought it would be needed for
5786 Do not delete it until we prove whether needed for Win9x though */
5787int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005788CIFSSMBSetAttrLegacy(unsigned int xid, struct cifs_tcon *tcon, char *fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005789 __u16 dos_attrs, const struct nls_table *nls_codepage)
5790{
5791 SETATTR_REQ *pSMB = NULL;
5792 SETATTR_RSP *pSMBr = NULL;
5793 int rc = 0;
5794 int bytes_returned;
5795 int name_len;
5796
Joe Perchesb6b38f72010-04-21 03:50:45 +00005797 cFYI(1, "In SetAttrLegacy");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005798
5799SetAttrLgcyRetry:
5800 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5801 (void **) &pSMBr);
5802 if (rc)
5803 return rc;
5804
5805 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5806 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005807 ConvertToUTF16((__le16 *) pSMB->fileName, fileName,
5808 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005809 name_len++; /* trailing null */
5810 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005811 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005812 name_len = strnlen(fileName, PATH_MAX);
5813 name_len++; /* trailing null */
5814 strncpy(pSMB->fileName, fileName, name_len);
5815 }
5816 pSMB->attr = cpu_to_le16(dos_attrs);
5817 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005818 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005819 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5820 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5821 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005822 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005823 cFYI(1, "Error in LegacySetAttr = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005824
5825 cifs_buf_release(pSMB);
5826
5827 if (rc == -EAGAIN)
5828 goto SetAttrLgcyRetry;
5829
5830 return rc;
5831}
5832#endif /* temporarily unneeded SetAttr legacy function */
5833
Jeff Layton654cf142009-07-09 20:02:49 -04005834static void
5835cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5836 const struct cifs_unix_set_info_args *args)
5837{
5838 u64 mode = args->mode;
5839
5840 /*
5841 * Samba server ignores set of file size to zero due to bugs in some
5842 * older clients, but we should be precise - we use SetFileSize to
5843 * set file size and do not want to truncate file size to zero
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005844 * accidentally as happened on one Samba server beta by putting
Jeff Layton654cf142009-07-09 20:02:49 -04005845 * zero instead of -1 here
5846 */
5847 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5848 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5849 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5850 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5851 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5852 data_offset->Uid = cpu_to_le64(args->uid);
5853 data_offset->Gid = cpu_to_le64(args->gid);
5854 /* better to leave device as zero when it is */
5855 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5856 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5857 data_offset->Permissions = cpu_to_le64(mode);
5858
5859 if (S_ISREG(mode))
5860 data_offset->Type = cpu_to_le32(UNIX_FILE);
5861 else if (S_ISDIR(mode))
5862 data_offset->Type = cpu_to_le32(UNIX_DIR);
5863 else if (S_ISLNK(mode))
5864 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5865 else if (S_ISCHR(mode))
5866 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5867 else if (S_ISBLK(mode))
5868 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5869 else if (S_ISFIFO(mode))
5870 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5871 else if (S_ISSOCK(mode))
5872 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5873}
5874
Linus Torvalds1da177e2005-04-16 15:20:36 -07005875int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005876CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005877 const struct cifs_unix_set_info_args *args,
5878 u16 fid, u32 pid_of_opener)
5879{
5880 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005881 char *data_offset;
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005882 int rc = 0;
5883 u16 params, param_offset, offset, byte_count, count;
5884
Joe Perchesb6b38f72010-04-21 03:50:45 +00005885 cFYI(1, "Set Unix Info (via SetFileInfo)");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005886 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5887
5888 if (rc)
5889 return rc;
5890
5891 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5892 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5893
5894 params = 6;
5895 pSMB->MaxSetupCount = 0;
5896 pSMB->Reserved = 0;
5897 pSMB->Flags = 0;
5898 pSMB->Timeout = 0;
5899 pSMB->Reserved2 = 0;
5900 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5901 offset = param_offset + params;
5902
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005903 data_offset = (char *)pSMB +
5904 offsetof(struct smb_hdr, Protocol) + offset;
5905
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005906 count = sizeof(FILE_UNIX_BASIC_INFO);
5907
5908 pSMB->MaxParameterCount = cpu_to_le16(2);
5909 /* BB find max SMB PDU from sess */
5910 pSMB->MaxDataCount = cpu_to_le16(1000);
5911 pSMB->SetupCount = 1;
5912 pSMB->Reserved3 = 0;
5913 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5914 byte_count = 3 /* pad */ + params + count;
5915 pSMB->DataCount = cpu_to_le16(count);
5916 pSMB->ParameterCount = cpu_to_le16(params);
5917 pSMB->TotalDataCount = pSMB->DataCount;
5918 pSMB->TotalParameterCount = pSMB->ParameterCount;
5919 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5920 pSMB->DataOffset = cpu_to_le16(offset);
5921 pSMB->Fid = fid;
5922 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5923 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005924 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005925 pSMB->ByteCount = cpu_to_le16(byte_count);
5926
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005927 cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005928
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005929 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005930 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005931 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005932
5933 /* Note: On -EAGAIN error only caller can retry on handle based calls
5934 since file handle passed in no longer valid */
5935
5936 return rc;
5937}
5938
5939int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005940CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005941 const char *file_name,
Jeff Layton01ea95e2009-07-09 20:02:49 -04005942 const struct cifs_unix_set_info_args *args,
5943 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005944{
5945 TRANSACTION2_SPI_REQ *pSMB = NULL;
5946 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5947 int name_len;
5948 int rc = 0;
5949 int bytes_returned = 0;
5950 FILE_UNIX_BASIC_INFO *data_offset;
5951 __u16 params, param_offset, offset, count, byte_count;
5952
Joe Perchesb6b38f72010-04-21 03:50:45 +00005953 cFYI(1, "In SetUID/GID/Mode");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005954setPermsRetry:
5955 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5956 (void **) &pSMBr);
5957 if (rc)
5958 return rc;
5959
5960 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5961 name_len =
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005962 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06005963 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005964 name_len++; /* trailing null */
5965 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005966 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005967 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005968 name_len++; /* trailing null */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005969 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005970 }
5971
5972 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005973 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005974 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005975 /* BB find max SMB PDU from sess structure BB */
5976 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005977 pSMB->MaxSetupCount = 0;
5978 pSMB->Reserved = 0;
5979 pSMB->Flags = 0;
5980 pSMB->Timeout = 0;
5981 pSMB->Reserved2 = 0;
5982 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005983 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005984 offset = param_offset + params;
5985 data_offset =
5986 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5987 offset);
5988 memset(data_offset, 0, count);
5989 pSMB->DataOffset = cpu_to_le16(offset);
5990 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5991 pSMB->SetupCount = 1;
5992 pSMB->Reserved3 = 0;
5993 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5994 byte_count = 3 /* pad */ + params + count;
5995 pSMB->ParameterCount = cpu_to_le16(params);
5996 pSMB->DataCount = cpu_to_le16(count);
5997 pSMB->TotalParameterCount = pSMB->ParameterCount;
5998 pSMB->TotalDataCount = pSMB->DataCount;
5999 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6000 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006001 inc_rfc1001_len(pSMB, byte_count);
Steve French50c2f752007-07-13 00:33:32 +00006002
Jeff Layton654cf142009-07-09 20:02:49 -04006003 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006004
6005 pSMB->ByteCount = cpu_to_le16(byte_count);
6006 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6007 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006008 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00006009 cFYI(1, "SetPathInfo (perms) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006010
Steve French0d817bc2008-05-22 02:02:03 +00006011 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006012 if (rc == -EAGAIN)
6013 goto setPermsRetry;
6014 return rc;
6015}
6016
Linus Torvalds1da177e2005-04-16 15:20:36 -07006017#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05006018/*
6019 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
6020 * function used by listxattr and getxattr type calls. When ea_name is set,
6021 * it looks for that attribute name and stuffs that value into the EAData
6022 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
6023 * buffer. In both cases, the return value is either the length of the
6024 * resulting data or a negative error code. If EAData is a NULL pointer then
6025 * the data isn't copied to it, but the length is returned.
6026 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006027ssize_t
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006028CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05006029 const unsigned char *searchName, const unsigned char *ea_name,
6030 char *EAData, size_t buf_size,
6031 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006032{
6033 /* BB assumes one setup word */
6034 TRANSACTION2_QPI_REQ *pSMB = NULL;
6035 TRANSACTION2_QPI_RSP *pSMBr = NULL;
6036 int rc = 0;
6037 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05006038 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006039 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00006040 struct fea *temp_fea;
6041 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006042 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006043 __u16 params, byte_count, data_offset;
Jeff Layton5980fc92011-07-28 12:48:26 -04006044 unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006045
Joe Perchesb6b38f72010-04-21 03:50:45 +00006046 cFYI(1, "In Query All EAs path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006047QAllEAsRetry:
6048 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6049 (void **) &pSMBr);
6050 if (rc)
6051 return rc;
6052
6053 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05006054 list_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006055 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
6056 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05006057 list_len++; /* trailing null */
6058 list_len *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006059 } else { /* BB improve the check for buffer overruns BB */
Jeff Layton6e462b92010-02-10 16:18:26 -05006060 list_len = strnlen(searchName, PATH_MAX);
6061 list_len++; /* trailing null */
6062 strncpy(pSMB->FileName, searchName, list_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006063 }
6064
Jeff Layton6e462b92010-02-10 16:18:26 -05006065 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006066 pSMB->TotalDataCount = 0;
6067 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006068 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05006069 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006070 pSMB->MaxSetupCount = 0;
6071 pSMB->Reserved = 0;
6072 pSMB->Flags = 0;
6073 pSMB->Timeout = 0;
6074 pSMB->Reserved2 = 0;
6075 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00006076 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006077 pSMB->DataCount = 0;
6078 pSMB->DataOffset = 0;
6079 pSMB->SetupCount = 1;
6080 pSMB->Reserved3 = 0;
6081 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
6082 byte_count = params + 1 /* pad */ ;
6083 pSMB->TotalParameterCount = cpu_to_le16(params);
6084 pSMB->ParameterCount = pSMB->TotalParameterCount;
6085 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
6086 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006087 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006088 pSMB->ByteCount = cpu_to_le16(byte_count);
6089
6090 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6091 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6092 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006093 cFYI(1, "Send error in QueryAllEAs = %d", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05006094 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006095 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006096
6097
6098 /* BB also check enough total bytes returned */
6099 /* BB we need to improve the validity checking
6100 of these trans2 responses */
6101
6102 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Jeff Layton820a8032011-05-04 08:05:26 -04006103 if (rc || get_bcc(&pSMBr->hdr) < 4) {
Jeff Laytonf0d38682010-02-10 16:18:26 -05006104 rc = -EIO; /* bad smb */
6105 goto QAllEAsOut;
6106 }
6107
6108 /* check that length of list is not more than bcc */
6109 /* check that each entry does not go beyond length
6110 of list */
6111 /* check that each element of each entry does not
6112 go beyond end of list */
6113 /* validate_trans2_offsets() */
6114 /* BB check if start of smb + data_offset > &bcc+ bcc */
6115
6116 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
6117 ea_response_data = (struct fealist *)
6118 (((char *) &pSMBr->hdr.Protocol) + data_offset);
6119
Jeff Layton6e462b92010-02-10 16:18:26 -05006120 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesb6b38f72010-04-21 03:50:45 +00006121 cFYI(1, "ea length %d", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05006122 if (list_len <= 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006123 cFYI(1, "empty EA list returned from server");
Jeff Laytonf0d38682010-02-10 16:18:26 -05006124 goto QAllEAsOut;
6125 }
6126
Jeff Layton0cd126b2010-02-10 16:18:26 -05006127 /* make sure list_len doesn't go past end of SMB */
Jeff Layton690c5222011-01-20 13:36:51 -05006128 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
Jeff Layton0cd126b2010-02-10 16:18:26 -05006129 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006130 cFYI(1, "EA list appears to go beyond SMB");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006131 rc = -EIO;
6132 goto QAllEAsOut;
6133 }
6134
Jeff Laytonf0d38682010-02-10 16:18:26 -05006135 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05006136 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006137 temp_fea = ea_response_data->list;
6138 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05006139 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00006140 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006141 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006142
Jeff Layton6e462b92010-02-10 16:18:26 -05006143 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006144 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006145 /* make sure we can read name_len and value_len */
6146 if (list_len < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006147 cFYI(1, "EA entry goes beyond length of list");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006148 rc = -EIO;
6149 goto QAllEAsOut;
6150 }
6151
6152 name_len = temp_fea->name_len;
6153 value_len = le16_to_cpu(temp_fea->value_len);
6154 list_len -= name_len + 1 + value_len;
6155 if (list_len < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006156 cFYI(1, "EA entry goes beyond length of list");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006157 rc = -EIO;
6158 goto QAllEAsOut;
6159 }
6160
Jeff Layton31c05192010-02-10 16:18:26 -05006161 if (ea_name) {
Jeff Layton91d065c2011-07-26 18:23:47 -04006162 if (ea_name_len == name_len &&
Jeff Laytonac423442011-10-11 06:41:32 -04006163 memcmp(ea_name, temp_ptr, name_len) == 0) {
Jeff Layton31c05192010-02-10 16:18:26 -05006164 temp_ptr += name_len + 1;
6165 rc = value_len;
6166 if (buf_size == 0)
6167 goto QAllEAsOut;
6168 if ((size_t)value_len > buf_size) {
6169 rc = -ERANGE;
6170 goto QAllEAsOut;
6171 }
6172 memcpy(EAData, temp_ptr, value_len);
6173 goto QAllEAsOut;
6174 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006175 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05006176 /* account for prefix user. and trailing null */
6177 rc += (5 + 1 + name_len);
6178 if (rc < (int) buf_size) {
6179 memcpy(EAData, "user.", 5);
6180 EAData += 5;
6181 memcpy(EAData, temp_ptr, name_len);
6182 EAData += name_len;
6183 /* null terminate name */
6184 *EAData = 0;
6185 ++EAData;
6186 } else if (buf_size == 0) {
6187 /* skip copy - calc size only */
6188 } else {
6189 /* stop before overrun buffer */
6190 rc = -ERANGE;
6191 break;
6192 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006193 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05006194 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006195 temp_fea = (struct fea *)temp_ptr;
6196 }
6197
Jeff Layton31c05192010-02-10 16:18:26 -05006198 /* didn't find the named attribute */
6199 if (ea_name)
6200 rc = -ENODATA;
6201
Jeff Laytonf0d38682010-02-10 16:18:26 -05006202QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00006203 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006204 if (rc == -EAGAIN)
6205 goto QAllEAsRetry;
6206
6207 return (ssize_t)rc;
6208}
6209
Linus Torvalds1da177e2005-04-16 15:20:36 -07006210int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006211CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
6212 const char *fileName, const char *ea_name, const void *ea_value,
Steve French50c2f752007-07-13 00:33:32 +00006213 const __u16 ea_value_len, const struct nls_table *nls_codepage,
6214 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006215{
6216 struct smb_com_transaction2_spi_req *pSMB = NULL;
6217 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
6218 struct fealist *parm_data;
6219 int name_len;
6220 int rc = 0;
6221 int bytes_returned = 0;
6222 __u16 params, param_offset, byte_count, offset, count;
6223
Joe Perchesb6b38f72010-04-21 03:50:45 +00006224 cFYI(1, "In SetEA");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006225SetEARetry:
6226 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6227 (void **) &pSMBr);
6228 if (rc)
6229 return rc;
6230
6231 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6232 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006233 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
6234 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006235 name_len++; /* trailing null */
6236 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00006237 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006238 name_len = strnlen(fileName, PATH_MAX);
6239 name_len++; /* trailing null */
6240 strncpy(pSMB->FileName, fileName, name_len);
6241 }
6242
6243 params = 6 + name_len;
6244
6245 /* done calculating parms using name_len of file name,
6246 now use name_len to calculate length of ea name
6247 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00006248 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006249 name_len = 0;
6250 else
Steve French50c2f752007-07-13 00:33:32 +00006251 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006252
Steve Frenchdae5dbd2007-12-30 23:49:57 +00006253 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006254 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006255 /* BB find max SMB PDU from sess */
6256 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006257 pSMB->MaxSetupCount = 0;
6258 pSMB->Reserved = 0;
6259 pSMB->Flags = 0;
6260 pSMB->Timeout = 0;
6261 pSMB->Reserved2 = 0;
6262 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006263 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006264 offset = param_offset + params;
6265 pSMB->InformationLevel =
6266 cpu_to_le16(SMB_SET_FILE_EA);
6267
6268 parm_data =
6269 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
6270 offset);
6271 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6272 pSMB->DataOffset = cpu_to_le16(offset);
6273 pSMB->SetupCount = 1;
6274 pSMB->Reserved3 = 0;
6275 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6276 byte_count = 3 /* pad */ + params + count;
6277 pSMB->DataCount = cpu_to_le16(count);
6278 parm_data->list_len = cpu_to_le32(count);
6279 parm_data->list[0].EA_flags = 0;
6280 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08006281 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006282 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00006283 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00006284 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006285 parm_data->list[0].name[name_len] = 0;
6286 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
6287 /* caller ensures that ea_value_len is less than 64K but
6288 we need to ensure that it fits within the smb */
6289
Steve French50c2f752007-07-13 00:33:32 +00006290 /*BB add length check to see if it would fit in
6291 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00006292 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
6293 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00006294 memcpy(parm_data->list[0].name+name_len+1,
6295 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006296
6297 pSMB->TotalDataCount = pSMB->DataCount;
6298 pSMB->ParameterCount = cpu_to_le16(params);
6299 pSMB->TotalParameterCount = pSMB->ParameterCount;
6300 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006301 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006302 pSMB->ByteCount = cpu_to_le16(byte_count);
6303 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6304 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006305 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00006306 cFYI(1, "SetPathInfo (EA) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006307
6308 cifs_buf_release(pSMB);
6309
6310 if (rc == -EAGAIN)
6311 goto SetEARetry;
6312
6313 return rc;
6314}
Linus Torvalds1da177e2005-04-16 15:20:36 -07006315#endif
Steve French0eff0e22011-02-24 05:39:23 +00006316
6317#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */
6318/*
6319 * Years ago the kernel added a "dnotify" function for Samba server,
6320 * to allow network clients (such as Windows) to display updated
6321 * lists of files in directory listings automatically when
6322 * files are added by one user when another user has the
6323 * same directory open on their desktop. The Linux cifs kernel
6324 * client hooked into the kernel side of this interface for
6325 * the same reason, but ironically when the VFS moved from
6326 * "dnotify" to "inotify" it became harder to plug in Linux
6327 * network file system clients (the most obvious use case
6328 * for notify interfaces is when multiple users can update
6329 * the contents of the same directory - exactly what network
6330 * file systems can do) although the server (Samba) could
6331 * still use it. For the short term we leave the worker
6332 * function ifdeffed out (below) until inotify is fixed
6333 * in the VFS to make it easier to plug in network file
6334 * system clients. If inotify turns out to be permanently
6335 * incompatible for network fs clients, we could instead simply
6336 * expose this config flag by adding a future cifs (and smb2) notify ioctl.
6337 */
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006338int CIFSSMBNotify(const unsigned int xid, struct cifs_tcon *tcon,
Steve French0eff0e22011-02-24 05:39:23 +00006339 const int notify_subdirs, const __u16 netfid,
6340 __u32 filter, struct file *pfile, int multishot,
6341 const struct nls_table *nls_codepage)
6342{
6343 int rc = 0;
6344 struct smb_com_transaction_change_notify_req *pSMB = NULL;
6345 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
6346 struct dir_notify_req *dnotify_req;
6347 int bytes_returned;
6348
6349 cFYI(1, "In CIFSSMBNotify for file handle %d", (int)netfid);
6350 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
6351 (void **) &pSMBr);
6352 if (rc)
6353 return rc;
6354
6355 pSMB->TotalParameterCount = 0 ;
6356 pSMB->TotalDataCount = 0;
6357 pSMB->MaxParameterCount = cpu_to_le32(2);
Jeff Laytonc974bef2011-10-11 06:41:32 -04006358 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Steve French0eff0e22011-02-24 05:39:23 +00006359 pSMB->MaxSetupCount = 4;
6360 pSMB->Reserved = 0;
6361 pSMB->ParameterOffset = 0;
6362 pSMB->DataCount = 0;
6363 pSMB->DataOffset = 0;
6364 pSMB->SetupCount = 4; /* single byte does not need le conversion */
6365 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
6366 pSMB->ParameterCount = pSMB->TotalParameterCount;
6367 if (notify_subdirs)
6368 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
6369 pSMB->Reserved2 = 0;
6370 pSMB->CompletionFilter = cpu_to_le32(filter);
6371 pSMB->Fid = netfid; /* file handle always le */
6372 pSMB->ByteCount = 0;
6373
6374 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6375 (struct smb_hdr *)pSMBr, &bytes_returned,
6376 CIFS_ASYNC_OP);
6377 if (rc) {
6378 cFYI(1, "Error in Notify = %d", rc);
6379 } else {
6380 /* Add file to outstanding requests */
6381 /* BB change to kmem cache alloc */
6382 dnotify_req = kmalloc(
6383 sizeof(struct dir_notify_req),
6384 GFP_KERNEL);
6385 if (dnotify_req) {
6386 dnotify_req->Pid = pSMB->hdr.Pid;
6387 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
6388 dnotify_req->Mid = pSMB->hdr.Mid;
6389 dnotify_req->Tid = pSMB->hdr.Tid;
6390 dnotify_req->Uid = pSMB->hdr.Uid;
6391 dnotify_req->netfid = netfid;
6392 dnotify_req->pfile = pfile;
6393 dnotify_req->filter = filter;
6394 dnotify_req->multishot = multishot;
6395 spin_lock(&GlobalMid_Lock);
6396 list_add_tail(&dnotify_req->lhead,
6397 &GlobalDnotifyReqList);
6398 spin_unlock(&GlobalMid_Lock);
6399 } else
6400 rc = -ENOMEM;
6401 }
6402 cifs_buf_release(pSMB);
6403 return rc;
6404}
6405#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */