blob: 1e7a4fe1f810faf58c19d98d7fdf1bf12bffa83d [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 Frencha45443472005-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 Frencha45443472005-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 Layton99d86c82011-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
Jeff Layton58195752012-09-19 06:22:34 -07001439 rdata->iov.iov_base = buf + HEADER_SIZE(server) - 1;
1440 rdata->iov.iov_len = len;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001441
Jeff Layton58195752012-09-19 06:22:34 -07001442 length = cifs_readv_from_socket(server, &rdata->iov, 1, len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001443 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 */
Jeff Layton58195752012-09-19 06:22:34 -07001488 rdata->iov.iov_base = buf + server->total_read;
1489 rdata->iov.iov_len = len;
1490 length = cifs_readv_from_socket(server, &rdata->iov, 1, len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001491 if (length < 0)
1492 return length;
1493 server->total_read += length;
1494 }
1495
1496 /* set up first iov for signature check */
Jeff Layton58195752012-09-19 06:22:34 -07001497 rdata->iov.iov_base = buf;
1498 rdata->iov.iov_len = server->total_read;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001499 cFYI(1, "0: iov_base=%p iov_len=%zu",
Jeff Layton58195752012-09-19 06:22:34 -07001500 rdata->iov.iov_base, rdata->iov.iov_len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001501
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
Jeff Layton8321fec2012-09-19 06:22:32 -07001510 length = rdata->read_into_pages(server, rdata, data_len);
1511 if (length < 0)
1512 return length;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001513
Jeff Layton8321fec2012-09-19 06:22:32 -07001514 server->total_read += length;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001515 rdata->bytes = length;
1516
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001517 cFYI(1, "total_read=%u buflen=%u remaining=%u", server->total_read,
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001518 buflen, data_len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001519
1520 /* discard anything left over */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001521 if (server->total_read < buflen)
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001522 return cifs_readv_discard(server, mid);
1523
1524 dequeue_mid(mid, false);
1525 return length;
1526}
1527
1528static void
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001529cifs_readv_callback(struct mid_q_entry *mid)
1530{
1531 struct cifs_readdata *rdata = mid->callback_data;
1532 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1533 struct TCP_Server_Info *server = tcon->ses->server;
Jeff Layton58195752012-09-19 06:22:34 -07001534 struct smb_rqst rqst = { .rq_iov = &rdata->iov,
1535 .rq_nvec = 1,
Jeff Layton8321fec2012-09-19 06:22:32 -07001536 .rq_pages = rdata->pages,
1537 .rq_npages = rdata->nr_pages,
1538 .rq_pagesz = rdata->pagesz,
1539 .rq_tailsz = rdata->tailsz };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001540
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001541 cFYI(1, "%s: mid=%llu state=%d result=%d bytes=%u", __func__,
1542 mid->mid, mid->mid_state, rdata->result, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001543
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001544 switch (mid->mid_state) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001545 case MID_RESPONSE_RECEIVED:
1546 /* result already set, check signature */
1547 if (server->sec_mode &
1548 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
Steve French985e4ff02012-08-03 09:42:45 -05001549 int rc = 0;
1550
Jeff Laytonbf5ea0e2012-09-18 16:20:34 -07001551 rc = cifs_verify_signature(&rqst, server,
1552 mid->sequence_number + 1);
Steve French985e4ff02012-08-03 09:42:45 -05001553 if (rc)
1554 cERROR(1, "SMB signature verification returned "
1555 "error = %d", rc);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001556 }
1557 /* FIXME: should this be counted toward the initiating task? */
1558 task_io_account_read(rdata->bytes);
1559 cifs_stats_bytes_read(tcon, rdata->bytes);
1560 break;
1561 case MID_REQUEST_SUBMITTED:
1562 case MID_RETRY_NEEDED:
1563 rdata->result = -EAGAIN;
1564 break;
1565 default:
1566 rdata->result = -EIO;
1567 }
1568
Jeff Laytonda472fc2012-03-23 14:40:53 -04001569 queue_work(cifsiod_wq, &rdata->work);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001570 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04001571 add_credits(server, 1, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001572}
1573
1574/* cifs_async_readv - send an async write, and set up mid to handle result */
1575int
1576cifs_async_readv(struct cifs_readdata *rdata)
1577{
1578 int rc;
1579 READ_REQ *smb = NULL;
1580 int wct;
1581 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
Jeff Layton58195752012-09-19 06:22:34 -07001582 struct smb_rqst rqst = { .rq_iov = &rdata->iov,
Jeff Laytonfec344e2012-09-18 16:20:35 -07001583 .rq_nvec = 1 };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001584
1585 cFYI(1, "%s: offset=%llu bytes=%u", __func__,
1586 rdata->offset, rdata->bytes);
1587
1588 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1589 wct = 12;
1590 else {
1591 wct = 10; /* old style read */
1592 if ((rdata->offset >> 32) > 0) {
1593 /* can not handle this big offset for old */
1594 return -EIO;
1595 }
1596 }
1597
1598 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **)&smb);
1599 if (rc)
1600 return rc;
1601
1602 smb->hdr.Pid = cpu_to_le16((__u16)rdata->pid);
1603 smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16));
1604
1605 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07001606 smb->Fid = rdata->cfile->fid.netfid;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001607 smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF);
1608 if (wct == 12)
1609 smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32);
1610 smb->Remaining = 0;
1611 smb->MaxCount = cpu_to_le16(rdata->bytes & 0xFFFF);
1612 smb->MaxCountHigh = cpu_to_le32(rdata->bytes >> 16);
1613 if (wct == 12)
1614 smb->ByteCount = 0;
1615 else {
1616 /* old style read */
1617 struct smb_com_readx_req *smbr =
1618 (struct smb_com_readx_req *)smb;
1619 smbr->ByteCount = 0;
1620 }
1621
1622 /* 4 for RFC1001 length + 1 for BCC */
Jeff Layton58195752012-09-19 06:22:34 -07001623 rdata->iov.iov_base = smb;
1624 rdata->iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001625
Jeff Layton6993f742012-05-16 07:13:17 -04001626 kref_get(&rdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07001627 rc = cifs_call_async(tcon->ses->server, &rqst, cifs_readv_receive,
1628 cifs_readv_callback, rdata, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001629
1630 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001631 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Jeff Layton6993f742012-05-16 07:13:17 -04001632 else
1633 kref_put(&rdata->refcount, cifs_readdata_release);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001634
1635 cifs_small_buf_release(smb);
1636 return rc;
1637}
1638
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001640CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
1641 unsigned int *nbytes, char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642{
1643 int rc = -EACCES;
1644 READ_REQ *pSMB = NULL;
1645 READ_RSP *pSMBr = NULL;
1646 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001647 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001648 int resp_buf_type = 0;
1649 struct kvec iov[1];
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001650 __u32 pid = io_parms->pid;
1651 __u16 netfid = io_parms->netfid;
1652 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001653 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001654 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655
Joe Perchesb6b38f72010-04-21 03:50:45 +00001656 cFYI(1, "Reading %d bytes on fid %d", count, netfid);
Steve French790fe572007-07-07 19:25:05 +00001657 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001658 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001659 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001660 wct = 10; /* old style read */
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001661 if ((offset >> 32) > 0) {
Steve French4c3130e2008-12-09 00:28:16 +00001662 /* can not handle this big offset for old */
1663 return -EIO;
1664 }
1665 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001666
1667 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001668 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669 if (rc)
1670 return rc;
1671
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001672 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1673 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1674
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675 /* tcon and ses pointer are checked in smb_init */
1676 if (tcon->ses->server == NULL)
1677 return -ECONNABORTED;
1678
Steve Frenchec637e32005-12-12 20:53:18 -08001679 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680 pSMB->Fid = netfid;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001681 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001682 if (wct == 12)
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001683 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001684
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685 pSMB->Remaining = 0;
1686 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1687 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001688 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001689 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1690 else {
1691 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001692 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001693 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001694 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001695 }
Steve Frenchec637e32005-12-12 20:53:18 -08001696
1697 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001698 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve Frencha761ac52007-10-18 21:45:27 +00001699 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Jeff Layton77499812011-01-11 07:24:23 -05001700 &resp_buf_type, CIFS_LOG_ERROR);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001701 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001702 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001704 cERROR(1, "Send error in read = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705 } else {
1706 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1707 data_length = data_length << 16;
1708 data_length += le16_to_cpu(pSMBr->DataLength);
1709 *nbytes = data_length;
1710
1711 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001712 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713 || (data_length > count)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001714 cFYI(1, "bad length %d for count %d",
1715 data_length, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716 rc = -EIO;
1717 *nbytes = 0;
1718 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001719 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001720 le16_to_cpu(pSMBr->DataOffset);
1721/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001722 cERROR(1, "Faulting on read rc = %d",rc);
Steve French50c2f752007-07-13 00:33:32 +00001723 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001724 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001725 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001726 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727 }
1728 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729
Steve French4b8f9302006-02-26 16:41:18 +00001730/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001731 if (*buf) {
1732 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001733 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001734 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001735 cifs_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001736 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001737 /* return buffer to caller to free */
1738 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001739 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001740 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001741 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001742 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001743 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001744
1745 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746 since file handle passed in no longer valid */
1747 return rc;
1748}
1749
Steve Frenchec637e32005-12-12 20:53:18 -08001750
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001752CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001753 unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001754 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755{
1756 int rc = -EACCES;
1757 WRITE_REQ *pSMB = NULL;
1758 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001759 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001760 __u32 bytes_sent;
1761 __u16 byte_count;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001762 __u32 pid = io_parms->pid;
1763 __u16 netfid = io_parms->netfid;
1764 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001765 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001766 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767
Steve Frencha24e2d72010-04-03 17:20:21 +00001768 *nbytes = 0;
1769
Joe Perchesb6b38f72010-04-21 03:50:45 +00001770 /* cFYI(1, "write at %lld %d bytes", offset, count);*/
Steve French790fe572007-07-07 19:25:05 +00001771 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001772 return -ECONNABORTED;
1773
Steve French790fe572007-07-07 19:25:05 +00001774 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001775 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001776 else {
Steve French1c955182005-08-30 20:58:07 -07001777 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001778 if ((offset >> 32) > 0) {
1779 /* can not handle big offset for old srv */
1780 return -EIO;
1781 }
1782 }
Steve French1c955182005-08-30 20:58:07 -07001783
1784 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785 (void **) &pSMBr);
1786 if (rc)
1787 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001788
1789 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1790 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1791
Linus Torvalds1da177e2005-04-16 15:20:36 -07001792 /* tcon and ses pointer are checked in smb_init */
1793 if (tcon->ses->server == NULL)
1794 return -ECONNABORTED;
1795
1796 pSMB->AndXCommand = 0xFF; /* none */
1797 pSMB->Fid = netfid;
1798 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001799 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001800 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001801
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802 pSMB->Reserved = 0xFFFFFFFF;
1803 pSMB->WriteMode = 0;
1804 pSMB->Remaining = 0;
1805
Steve French50c2f752007-07-13 00:33:32 +00001806 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807 can send more if LARGE_WRITE_X capability returned by the server and if
1808 our buffer is big enough or if we convert to iovecs on socket writes
1809 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001810 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1812 } else {
1813 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1814 & ~0xFF;
1815 }
1816
1817 if (bytes_sent > count)
1818 bytes_sent = count;
1819 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001820 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001821 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001822 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001823 else if (ubuf) {
1824 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001825 cifs_buf_release(pSMB);
1826 return -EFAULT;
1827 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001828 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001829 /* No buffer */
1830 cifs_buf_release(pSMB);
1831 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001832 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001833 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001834 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001835 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001836 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001837
Linus Torvalds1da177e2005-04-16 15:20:36 -07001838 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1839 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001840 inc_rfc1001_len(pSMB, byte_count);
Steve French1c955182005-08-30 20:58:07 -07001841
Steve French790fe572007-07-07 19:25:05 +00001842 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001843 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001844 else { /* old style write has byte count 4 bytes earlier
1845 so 4 bytes pad */
1846 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001847 (struct smb_com_writex_req *)pSMB;
1848 pSMBW->ByteCount = cpu_to_le16(byte_count);
1849 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850
1851 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1852 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001853 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00001855 cFYI(1, "Send error in write = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856 } else {
1857 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1858 *nbytes = (*nbytes) << 16;
1859 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301860
1861 /*
1862 * Mask off high 16 bits when bytes written as returned by the
1863 * server is greater than bytes requested by the client. Some
1864 * OS/2 servers are known to set incorrect CountHigh values.
1865 */
1866 if (*nbytes > count)
1867 *nbytes &= 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868 }
1869
1870 cifs_buf_release(pSMB);
1871
Steve French50c2f752007-07-13 00:33:32 +00001872 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873 since file handle passed in no longer valid */
1874
1875 return rc;
1876}
1877
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001878void
1879cifs_writedata_release(struct kref *refcount)
1880{
1881 struct cifs_writedata *wdata = container_of(refcount,
1882 struct cifs_writedata, refcount);
1883
1884 if (wdata->cfile)
1885 cifsFileInfo_put(wdata->cfile);
1886
1887 kfree(wdata);
1888}
1889
1890/*
1891 * Write failed with a retryable error. Resend the write request. It's also
1892 * possible that the page was redirtied so re-clean the page.
1893 */
1894static void
1895cifs_writev_requeue(struct cifs_writedata *wdata)
1896{
1897 int i, rc;
1898 struct inode *inode = wdata->cfile->dentry->d_inode;
Pavel Shilovskyc9de5c82012-09-18 16:20:29 -07001899 struct TCP_Server_Info *server;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001900
1901 for (i = 0; i < wdata->nr_pages; i++) {
1902 lock_page(wdata->pages[i]);
1903 clear_page_dirty_for_io(wdata->pages[i]);
1904 }
1905
1906 do {
Pavel Shilovskyc9de5c82012-09-18 16:20:29 -07001907 server = tlink_tcon(wdata->cfile->tlink)->ses->server;
1908 rc = server->ops->async_writev(wdata);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001909 } while (rc == -EAGAIN);
1910
1911 for (i = 0; i < wdata->nr_pages; i++) {
Jeff Layton94e18002013-03-04 15:18:25 -05001912 unlock_page(wdata->pages[i]);
Ouyang Maochunc51bb0e2013-02-18 09:54:52 -06001913 if (rc != 0) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001914 SetPageError(wdata->pages[i]);
Ouyang Maochunc51bb0e2013-02-18 09:54:52 -06001915 end_page_writeback(wdata->pages[i]);
1916 page_cache_release(wdata->pages[i]);
1917 }
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001918 }
1919
1920 mapping_set_error(inode->i_mapping, rc);
1921 kref_put(&wdata->refcount, cifs_writedata_release);
1922}
1923
Jeff Laytonc2e87642012-03-23 14:40:55 -04001924void
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001925cifs_writev_complete(struct work_struct *work)
1926{
1927 struct cifs_writedata *wdata = container_of(work,
1928 struct cifs_writedata, work);
1929 struct inode *inode = wdata->cfile->dentry->d_inode;
1930 int i = 0;
1931
1932 if (wdata->result == 0) {
Jeff Layton597b0272012-03-23 14:40:56 -04001933 spin_lock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001934 cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
Jeff Layton597b0272012-03-23 14:40:56 -04001935 spin_unlock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001936 cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
1937 wdata->bytes);
1938 } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
1939 return cifs_writev_requeue(wdata);
1940
1941 for (i = 0; i < wdata->nr_pages; i++) {
1942 struct page *page = wdata->pages[i];
1943 if (wdata->result == -EAGAIN)
1944 __set_page_dirty_nobuffers(page);
1945 else if (wdata->result < 0)
1946 SetPageError(page);
1947 end_page_writeback(page);
1948 page_cache_release(page);
1949 }
1950 if (wdata->result != -EAGAIN)
1951 mapping_set_error(inode->i_mapping, wdata->result);
1952 kref_put(&wdata->refcount, cifs_writedata_release);
1953}
1954
1955struct cifs_writedata *
Jeff Laytonc2e87642012-03-23 14:40:55 -04001956cifs_writedata_alloc(unsigned int nr_pages, work_func_t complete)
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001957{
1958 struct cifs_writedata *wdata;
1959
1960 /* this would overflow */
1961 if (nr_pages == 0) {
1962 cERROR(1, "%s: called with nr_pages == 0!", __func__);
1963 return NULL;
1964 }
1965
1966 /* writedata + number of page pointers */
1967 wdata = kzalloc(sizeof(*wdata) +
1968 sizeof(struct page *) * (nr_pages - 1), GFP_NOFS);
1969 if (wdata != NULL) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001970 kref_init(&wdata->refcount);
Jeff Laytonda82f7e2012-03-23 14:40:56 -04001971 INIT_LIST_HEAD(&wdata->list);
1972 init_completion(&wdata->done);
1973 INIT_WORK(&wdata->work, complete);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001974 }
1975 return wdata;
1976}
1977
1978/*
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001979 * Check the mid_state and signature on received buffer (if any), and queue the
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001980 * workqueue completion task.
1981 */
1982static void
1983cifs_writev_callback(struct mid_q_entry *mid)
1984{
1985 struct cifs_writedata *wdata = mid->callback_data;
Steve French96daf2b2011-05-27 04:34:02 +00001986 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001987 unsigned int written;
1988 WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
1989
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001990 switch (mid->mid_state) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001991 case MID_RESPONSE_RECEIVED:
1992 wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
1993 if (wdata->result != 0)
1994 break;
1995
1996 written = le16_to_cpu(smb->CountHigh);
1997 written <<= 16;
1998 written += le16_to_cpu(smb->Count);
1999 /*
2000 * Mask off high 16 bits when bytes written as returned
2001 * by the server is greater than bytes requested by the
2002 * client. OS/2 servers are known to set incorrect
2003 * CountHigh values.
2004 */
2005 if (written > wdata->bytes)
2006 written &= 0xFFFF;
2007
2008 if (written < wdata->bytes)
2009 wdata->result = -ENOSPC;
2010 else
2011 wdata->bytes = written;
2012 break;
2013 case MID_REQUEST_SUBMITTED:
2014 case MID_RETRY_NEEDED:
2015 wdata->result = -EAGAIN;
2016 break;
2017 default:
2018 wdata->result = -EIO;
2019 break;
2020 }
2021
Jeff Laytonda472fc2012-03-23 14:40:53 -04002022 queue_work(cifsiod_wq, &wdata->work);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002023 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002024 add_credits(tcon->ses->server, 1, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002025}
2026
2027/* cifs_async_writev - send an async write, and set up mid to handle result */
2028int
2029cifs_async_writev(struct cifs_writedata *wdata)
2030{
Jeff Laytoneddb0792012-09-18 16:20:35 -07002031 int rc = -EACCES;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002032 WRITE_REQ *smb = NULL;
2033 int wct;
Steve French96daf2b2011-05-27 04:34:02 +00002034 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytoneddb0792012-09-18 16:20:35 -07002035 struct kvec iov;
Jeff Laytonfec344e2012-09-18 16:20:35 -07002036 struct smb_rqst rqst = { };
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002037
2038 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
2039 wct = 14;
2040 } else {
2041 wct = 12;
2042 if (wdata->offset >> 32 > 0) {
2043 /* can not handle big offset for old srv */
2044 return -EIO;
2045 }
2046 }
2047
2048 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
2049 if (rc)
2050 goto async_writev_out;
2051
Jeff Laytonfe5f5d22012-03-23 14:40:55 -04002052 smb->hdr.Pid = cpu_to_le16((__u16)wdata->pid);
2053 smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16));
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002054
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002055 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07002056 smb->Fid = wdata->cfile->fid.netfid;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002057 smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
2058 if (wct == 14)
2059 smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
2060 smb->Reserved = 0xFFFFFFFF;
2061 smb->WriteMode = 0;
2062 smb->Remaining = 0;
2063
2064 smb->DataOffset =
2065 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
2066
2067 /* 4 for RFC1001 length + 1 for BCC */
Jeff Laytoneddb0792012-09-18 16:20:35 -07002068 iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4 + 1;
2069 iov.iov_base = smb;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002070
Jeff Laytoneddb0792012-09-18 16:20:35 -07002071 rqst.rq_iov = &iov;
2072 rqst.rq_nvec = 1;
2073 rqst.rq_pages = wdata->pages;
2074 rqst.rq_npages = wdata->nr_pages;
2075 rqst.rq_pagesz = wdata->pagesz;
2076 rqst.rq_tailsz = wdata->tailsz;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002077
2078 cFYI(1, "async write at %llu %u bytes", wdata->offset, wdata->bytes);
2079
2080 smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
2081 smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16);
2082
2083 if (wct == 14) {
2084 inc_rfc1001_len(&smb->hdr, wdata->bytes + 1);
2085 put_bcc(wdata->bytes + 1, &smb->hdr);
2086 } else {
2087 /* wct == 12 */
2088 struct smb_com_writex_req *smbw =
2089 (struct smb_com_writex_req *)smb;
2090 inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
2091 put_bcc(wdata->bytes + 5, &smbw->hdr);
Jeff Laytoneddb0792012-09-18 16:20:35 -07002092 iov.iov_len += 4; /* pad bigger by four bytes */
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002093 }
2094
2095 kref_get(&wdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07002096 rc = cifs_call_async(tcon->ses->server, &rqst, NULL,
2097 cifs_writev_callback, wdata, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002098
2099 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002100 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002101 else
2102 kref_put(&wdata->refcount, cifs_writedata_release);
2103
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002104async_writev_out:
2105 cifs_small_buf_release(smb);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002106 return rc;
2107}
2108
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002109int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002110CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
Pavel Shilovskyba9ad7252012-09-18 16:20:30 -07002111 unsigned int *nbytes, struct kvec *iov, int n_vec)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002112{
2113 int rc = -EACCES;
2114 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08002115 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002116 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08002117 int resp_buf_type = 0;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002118 __u32 pid = io_parms->pid;
2119 __u16 netfid = io_parms->netfid;
2120 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00002121 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002122 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002123
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04002124 *nbytes = 0;
2125
Joe Perchesb6b38f72010-04-21 03:50:45 +00002126 cFYI(1, "write2 at %lld %d bytes", (long long)offset, count);
Steve Frenchff7feac2005-11-15 16:45:16 -08002127
Steve French4c3130e2008-12-09 00:28:16 +00002128 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07002129 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00002130 } else {
Steve French8cc64c62005-10-03 13:49:43 -07002131 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00002132 if ((offset >> 32) > 0) {
2133 /* can not handle big offset for old srv */
2134 return -EIO;
2135 }
2136 }
Steve French8cc64c62005-10-03 13:49:43 -07002137 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002138 if (rc)
2139 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002140
2141 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
2142 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
2143
Linus Torvalds1da177e2005-04-16 15:20:36 -07002144 /* tcon and ses pointer are checked in smb_init */
2145 if (tcon->ses->server == NULL)
2146 return -ECONNABORTED;
2147
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002148 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002149 pSMB->Fid = netfid;
2150 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00002151 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002152 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002153 pSMB->Reserved = 0xFFFFFFFF;
2154 pSMB->WriteMode = 0;
2155 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002156
Linus Torvalds1da177e2005-04-16 15:20:36 -07002157 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00002158 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002159
Steve French3e844692005-10-03 13:37:24 -07002160 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
2161 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002162 /* header + 1 byte pad */
2163 smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
Steve French790fe572007-07-07 19:25:05 +00002164 if (wct == 14)
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002165 inc_rfc1001_len(pSMB, count + 1);
Steve French8cc64c62005-10-03 13:49:43 -07002166 else /* wct == 12 */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002167 inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
Steve French790fe572007-07-07 19:25:05 +00002168 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002169 pSMB->ByteCount = cpu_to_le16(count + 1);
2170 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00002171 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07002172 (struct smb_com_writex_req *)pSMB;
2173 pSMBW->ByteCount = cpu_to_le16(count + 5);
2174 }
Steve French3e844692005-10-03 13:37:24 -07002175 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00002176 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08002177 iov[0].iov_len = smb_hdr_len + 4;
2178 else /* wct == 12 pad bigger by four bytes */
2179 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00002180
Steve French3e844692005-10-03 13:37:24 -07002181
Pavel Shilovskyba9ad7252012-09-18 16:20:30 -07002182 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002183 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002184 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002185 cFYI(1, "Send error Write2 = %d", rc);
Steve French790fe572007-07-07 19:25:05 +00002186 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08002187 /* presumably this can not happen, but best to be safe */
2188 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002189 } else {
Steve Frenchad7a2922008-02-07 23:25:02 +00002190 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002191 *nbytes = le16_to_cpu(pSMBr->CountHigh);
2192 *nbytes = (*nbytes) << 16;
2193 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05302194
2195 /*
2196 * Mask off high 16 bits when bytes written as returned by the
2197 * server is greater than bytes requested by the client. OS/2
2198 * servers are known to set incorrect CountHigh values.
2199 */
2200 if (*nbytes > count)
2201 *nbytes &= 0xFFFF;
Steve French50c2f752007-07-13 00:33:32 +00002202 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002203
Steve French4b8f9302006-02-26 16:41:18 +00002204/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00002205 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002206 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00002207 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002208 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002209
Steve French50c2f752007-07-13 00:33:32 +00002210 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002211 since file handle passed in no longer valid */
2212
2213 return rc;
2214}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002215
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002216int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon,
2217 const __u16 netfid, const __u8 lock_type, const __u32 num_unlock,
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002218 const __u32 num_lock, LOCKING_ANDX_RANGE *buf)
2219{
2220 int rc = 0;
2221 LOCK_REQ *pSMB = NULL;
2222 struct kvec iov[2];
2223 int resp_buf_type;
2224 __u16 count;
2225
2226 cFYI(1, "cifs_lockv num lock %d num unlock %d", num_lock, num_unlock);
2227
2228 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2229 if (rc)
2230 return rc;
2231
2232 pSMB->Timeout = 0;
2233 pSMB->NumberOfLocks = cpu_to_le16(num_lock);
2234 pSMB->NumberOfUnlocks = cpu_to_le16(num_unlock);
2235 pSMB->LockType = lock_type;
2236 pSMB->AndXCommand = 0xFF; /* none */
2237 pSMB->Fid = netfid; /* netfid stays le */
2238
2239 count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2240 inc_rfc1001_len(pSMB, count);
2241 pSMB->ByteCount = cpu_to_le16(count);
2242
2243 iov[0].iov_base = (char *)pSMB;
2244 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 -
2245 (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2246 iov[1].iov_base = (char *)buf;
2247 iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2248
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002249 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002250 rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP);
2251 if (rc)
2252 cFYI(1, "Send error in cifs_lockv = %d", rc);
2253
2254 return rc;
2255}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002256
Linus Torvalds1da177e2005-04-16 15:20:36 -07002257int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002258CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002259 const __u16 smb_file_id, const __u32 netpid, const __u64 len,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002260 const __u64 offset, const __u32 numUnlock,
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002261 const __u32 numLock, const __u8 lockType,
2262 const bool waitFlag, const __u8 oplock_level)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002263{
2264 int rc = 0;
2265 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002266/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002267 int bytes_returned;
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002268 int flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002269 __u16 count;
2270
Joe Perchesb6b38f72010-04-21 03:50:45 +00002271 cFYI(1, "CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock);
Steve French46810cb2005-04-28 22:41:09 -07002272 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2273
Linus Torvalds1da177e2005-04-16 15:20:36 -07002274 if (rc)
2275 return rc;
2276
Steve French790fe572007-07-07 19:25:05 +00002277 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002278 /* no response expected */
2279 flags = CIFS_ASYNC_OP | CIFS_OBREAK_OP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002280 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00002281 } else if (waitFlag) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002282 flags = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002283 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
2284 } else {
2285 pSMB->Timeout = 0;
2286 }
2287
2288 pSMB->NumberOfLocks = cpu_to_le16(numLock);
2289 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
2290 pSMB->LockType = lockType;
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002291 pSMB->OplockLevel = oplock_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002292 pSMB->AndXCommand = 0xFF; /* none */
2293 pSMB->Fid = smb_file_id; /* netfid stays le */
2294
Steve French790fe572007-07-07 19:25:05 +00002295 if ((numLock != 0) || (numUnlock != 0)) {
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002296 pSMB->Locks[0].Pid = cpu_to_le16(netpid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002297 /* BB where to store pid high? */
2298 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
2299 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
2300 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
2301 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
2302 count = sizeof(LOCKING_ANDX_RANGE);
2303 } else {
2304 /* oplock break */
2305 count = 0;
2306 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002307 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002308 pSMB->ByteCount = cpu_to_le16(count);
2309
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002310 if (waitFlag) {
2311 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002312 (struct smb_hdr *) pSMB, &bytes_returned);
Steve French133672e2007-11-13 22:41:37 +00002313 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002314 } else {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002315 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, flags);
Steve French133672e2007-11-13 22:41:37 +00002316 /* SMB buffer freed by function above */
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002317 }
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002318 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002319 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002320 cFYI(1, "Send error in Lock = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002321
Steve French50c2f752007-07-13 00:33:32 +00002322 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323 since file handle passed in no longer valid */
2324 return rc;
2325}
2326
2327int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002328CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002329 const __u16 smb_file_id, const __u32 netpid,
2330 const loff_t start_offset, const __u64 len,
2331 struct file_lock *pLockData, const __u16 lock_type,
2332 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00002333{
2334 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2335 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00002336 struct cifs_posix_lock *parm_data;
2337 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00002338 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00002339 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00002340 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00002341 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00002342 struct kvec iov[1];
Steve French08547b02006-02-28 22:39:25 +00002343
Joe Perchesb6b38f72010-04-21 03:50:45 +00002344 cFYI(1, "Posix Lock");
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002345
Steve French08547b02006-02-28 22:39:25 +00002346 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
2347
2348 if (rc)
2349 return rc;
2350
2351 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
2352
Steve French50c2f752007-07-13 00:33:32 +00002353 params = 6;
Steve French08547b02006-02-28 22:39:25 +00002354 pSMB->MaxSetupCount = 0;
2355 pSMB->Reserved = 0;
2356 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00002357 pSMB->Reserved2 = 0;
2358 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2359 offset = param_offset + params;
2360
Steve French08547b02006-02-28 22:39:25 +00002361 count = sizeof(struct cifs_posix_lock);
2362 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002363 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00002364 pSMB->SetupCount = 1;
2365 pSMB->Reserved3 = 0;
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002366 if (pLockData)
Steve French08547b02006-02-28 22:39:25 +00002367 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2368 else
2369 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2370 byte_count = 3 /* pad */ + params + count;
2371 pSMB->DataCount = cpu_to_le16(count);
2372 pSMB->ParameterCount = cpu_to_le16(params);
2373 pSMB->TotalDataCount = pSMB->DataCount;
2374 pSMB->TotalParameterCount = pSMB->ParameterCount;
2375 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00002376 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00002377 (((char *) &pSMB->hdr.Protocol) + offset);
2378
2379 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00002380 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00002381 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00002382 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00002383 pSMB->Timeout = cpu_to_le32(-1);
2384 } else
2385 pSMB->Timeout = 0;
2386
Pavel Shilovsky4f6bcec2011-10-22 15:33:30 +04002387 parm_data->pid = cpu_to_le32(netpid);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002388 parm_data->start = cpu_to_le64(start_offset);
Steve Frenchcec6815a2006-05-30 18:07:17 +00002389 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00002390
2391 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00002392 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00002393 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
2394 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002395 inc_rfc1001_len(pSMB, byte_count);
Steve French08547b02006-02-28 22:39:25 +00002396 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002397 if (waitFlag) {
2398 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2399 (struct smb_hdr *) pSMBr, &bytes_returned);
2400 } else {
Steve French133672e2007-11-13 22:41:37 +00002401 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002402 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French133672e2007-11-13 22:41:37 +00002403 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
2404 &resp_buf_type, timeout);
2405 pSMB = NULL; /* request buf already freed by SendReceive2. Do
2406 not try to free it twice below on exit */
2407 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002408 }
2409
Steve French08547b02006-02-28 22:39:25 +00002410 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002411 cFYI(1, "Send error in Posix Lock = %d", rc);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002412 } else if (pLockData) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002413 /* lock structure can be returned on get */
2414 __u16 data_offset;
2415 __u16 data_count;
2416 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00002417
Jeff Layton820a8032011-05-04 08:05:26 -04002418 if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002419 rc = -EIO; /* bad smb */
2420 goto plk_err_exit;
2421 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002422 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2423 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00002424 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002425 rc = -EIO;
2426 goto plk_err_exit;
2427 }
2428 parm_data = (struct cifs_posix_lock *)
2429 ((char *)&pSMBr->hdr.Protocol + data_offset);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002430 if (parm_data->lock_type == __constant_cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002431 pLockData->fl_type = F_UNLCK;
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002432 else {
2433 if (parm_data->lock_type ==
2434 __constant_cpu_to_le16(CIFS_RDLCK))
2435 pLockData->fl_type = F_RDLCK;
2436 else if (parm_data->lock_type ==
2437 __constant_cpu_to_le16(CIFS_WRLCK))
2438 pLockData->fl_type = F_WRLCK;
2439
Steve French5443d132011-03-13 05:08:25 +00002440 pLockData->fl_start = le64_to_cpu(parm_data->start);
2441 pLockData->fl_end = pLockData->fl_start +
2442 le64_to_cpu(parm_data->length) - 1;
2443 pLockData->fl_pid = le32_to_cpu(parm_data->pid);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002444 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002445 }
Steve French50c2f752007-07-13 00:33:32 +00002446
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002447plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00002448 if (pSMB)
2449 cifs_small_buf_release(pSMB);
2450
Steve French133672e2007-11-13 22:41:37 +00002451 if (resp_buf_type == CIFS_SMALL_BUFFER)
2452 cifs_small_buf_release(iov[0].iov_base);
2453 else if (resp_buf_type == CIFS_LARGE_BUFFER)
2454 cifs_buf_release(iov[0].iov_base);
2455
Steve French08547b02006-02-28 22:39:25 +00002456 /* Note: On -EAGAIN error only caller can retry on handle based calls
2457 since file handle passed in no longer valid */
2458
2459 return rc;
2460}
2461
2462
2463int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002464CIFSSMBClose(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002465{
2466 int rc = 0;
2467 CLOSE_REQ *pSMB = NULL;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002468 cFYI(1, "In CIFSSMBClose");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002469
2470/* do not retry on dead session on close */
2471 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00002472 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002473 return 0;
2474 if (rc)
2475 return rc;
2476
Linus Torvalds1da177e2005-04-16 15:20:36 -07002477 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00002478 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002479 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002480 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002481 cifs_stats_inc(&tcon->stats.cifs_stats.num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002482 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00002483 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002484 /* EINTR is expected when user ctl-c to kill app */
Joe Perchesb6b38f72010-04-21 03:50:45 +00002485 cERROR(1, "Send error in Close = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002486 }
2487 }
2488
Linus Torvalds1da177e2005-04-16 15:20:36 -07002489 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00002490 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002491 rc = 0;
2492
2493 return rc;
2494}
2495
2496int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002497CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Steve Frenchb298f222009-02-21 21:17:43 +00002498{
2499 int rc = 0;
2500 FLUSH_REQ *pSMB = NULL;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002501 cFYI(1, "In CIFSSMBFlush");
Steve Frenchb298f222009-02-21 21:17:43 +00002502
2503 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
2504 if (rc)
2505 return rc;
2506
2507 pSMB->FileID = (__u16) smb_file_id;
2508 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002509 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002510 cifs_stats_inc(&tcon->stats.cifs_stats.num_flushes);
Steve Frenchb298f222009-02-21 21:17:43 +00002511 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002512 cERROR(1, "Send error in Flush = %d", rc);
Steve Frenchb298f222009-02-21 21:17:43 +00002513
2514 return rc;
2515}
2516
2517int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002518CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002519 const char *from_name, const char *to_name,
2520 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002521{
2522 int rc = 0;
2523 RENAME_REQ *pSMB = NULL;
2524 RENAME_RSP *pSMBr = NULL;
2525 int bytes_returned;
2526 int name_len, name_len2;
2527 __u16 count;
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002528 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529
Joe Perchesb6b38f72010-04-21 03:50:45 +00002530 cFYI(1, "In CIFSSMBRename");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002531renameRetry:
2532 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
2533 (void **) &pSMBr);
2534 if (rc)
2535 return rc;
2536
2537 pSMB->BufferFormat = 0x04;
2538 pSMB->SearchAttributes =
2539 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2540 ATTR_DIRECTORY);
2541
2542 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002543 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2544 from_name, PATH_MAX,
2545 cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002546 name_len++; /* trailing null */
2547 name_len *= 2;
2548 pSMB->OldFileName[name_len] = 0x04; /* pad */
2549 /* protocol requires ASCII signature byte on Unicode string */
2550 pSMB->OldFileName[name_len + 1] = 0x00;
2551 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002552 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002553 to_name, PATH_MAX, cifs_sb->local_nls,
2554 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002555 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2556 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002557 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002558 name_len = strnlen(from_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002559 name_len++; /* trailing null */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002560 strncpy(pSMB->OldFileName, from_name, name_len);
2561 name_len2 = strnlen(to_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002562 name_len2++; /* trailing null */
2563 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002564 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002565 name_len2++; /* trailing null */
2566 name_len2++; /* signature byte */
2567 }
2568
2569 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002570 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002571 pSMB->ByteCount = cpu_to_le16(count);
2572
2573 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2574 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002575 cifs_stats_inc(&tcon->stats.cifs_stats.num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002576 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002577 cFYI(1, "Send error in rename = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002578
Linus Torvalds1da177e2005-04-16 15:20:36 -07002579 cifs_buf_release(pSMB);
2580
2581 if (rc == -EAGAIN)
2582 goto renameRetry;
2583
2584 return rc;
2585}
2586
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002587int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002588 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002589 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002590{
2591 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2592 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002593 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002594 char *data_offset;
2595 char dummy_string[30];
2596 int rc = 0;
2597 int bytes_returned = 0;
2598 int len_of_str;
2599 __u16 params, param_offset, offset, count, byte_count;
2600
Joe Perchesb6b38f72010-04-21 03:50:45 +00002601 cFYI(1, "Rename to File by handle");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002602 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2603 (void **) &pSMBr);
2604 if (rc)
2605 return rc;
2606
2607 params = 6;
2608 pSMB->MaxSetupCount = 0;
2609 pSMB->Reserved = 0;
2610 pSMB->Flags = 0;
2611 pSMB->Timeout = 0;
2612 pSMB->Reserved2 = 0;
2613 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2614 offset = param_offset + params;
2615
2616 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2617 rename_info = (struct set_file_rename *) data_offset;
2618 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002619 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002620 pSMB->SetupCount = 1;
2621 pSMB->Reserved3 = 0;
2622 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2623 byte_count = 3 /* pad */ + params;
2624 pSMB->ParameterCount = cpu_to_le16(params);
2625 pSMB->TotalParameterCount = pSMB->ParameterCount;
2626 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2627 pSMB->DataOffset = cpu_to_le16(offset);
2628 /* construct random name ".cifs_tmp<inodenum><mid>" */
2629 rename_info->overwrite = cpu_to_le32(1);
2630 rename_info->root_fid = 0;
2631 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002632 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002633 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
Steve Frenchacbbb762012-01-18 22:32:33 -06002634 len_of_str =
2635 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002636 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002637 } else {
Steve Frenchacbbb762012-01-18 22:32:33 -06002638 len_of_str =
2639 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002640 target_name, PATH_MAX, nls_codepage,
2641 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002642 }
2643 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002644 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002645 byte_count += count;
2646 pSMB->DataCount = cpu_to_le16(count);
2647 pSMB->TotalDataCount = pSMB->DataCount;
2648 pSMB->Fid = netfid;
2649 pSMB->InformationLevel =
2650 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2651 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002652 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002653 pSMB->ByteCount = cpu_to_le16(byte_count);
2654 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002655 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002656 cifs_stats_inc(&pTcon->stats.cifs_stats.num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002657 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002658 cFYI(1, "Send error in Rename (by file handle) = %d", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07002659
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660 cifs_buf_release(pSMB);
2661
2662 /* Note: On -EAGAIN error only caller can retry on handle based calls
2663 since file handle passed in no longer valid */
2664
2665 return rc;
2666}
2667
2668int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002669CIFSSMBCopy(const unsigned int xid, struct cifs_tcon *tcon,
2670 const char *fromName, const __u16 target_tid, const char *toName,
2671 const int flags, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002672{
2673 int rc = 0;
2674 COPY_REQ *pSMB = NULL;
2675 COPY_RSP *pSMBr = NULL;
2676 int bytes_returned;
2677 int name_len, name_len2;
2678 __u16 count;
2679
Joe Perchesb6b38f72010-04-21 03:50:45 +00002680 cFYI(1, "In CIFSSMBCopy");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002681copyRetry:
2682 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2683 (void **) &pSMBr);
2684 if (rc)
2685 return rc;
2686
2687 pSMB->BufferFormat = 0x04;
2688 pSMB->Tid2 = target_tid;
2689
2690 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2691
2692 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002693 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2694 fromName, PATH_MAX, nls_codepage,
2695 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002696 name_len++; /* trailing null */
2697 name_len *= 2;
2698 pSMB->OldFileName[name_len] = 0x04; /* pad */
2699 /* protocol requires ASCII signature byte on Unicode string */
2700 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002701 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002702 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2703 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2705 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002706 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002707 name_len = strnlen(fromName, PATH_MAX);
2708 name_len++; /* trailing null */
2709 strncpy(pSMB->OldFileName, fromName, name_len);
2710 name_len2 = strnlen(toName, PATH_MAX);
2711 name_len2++; /* trailing null */
2712 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2713 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2714 name_len2++; /* trailing null */
2715 name_len2++; /* signature byte */
2716 }
2717
2718 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002719 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002720 pSMB->ByteCount = cpu_to_le16(count);
2721
2722 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2723 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2724 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002725 cFYI(1, "Send error in copy = %d with %d files copied",
2726 rc, le16_to_cpu(pSMBr->CopyCount));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002727 }
Steve French0d817bc2008-05-22 02:02:03 +00002728 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002729
2730 if (rc == -EAGAIN)
2731 goto copyRetry;
2732
2733 return rc;
2734}
2735
2736int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002737CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002738 const char *fromName, const char *toName,
2739 const struct nls_table *nls_codepage)
2740{
2741 TRANSACTION2_SPI_REQ *pSMB = NULL;
2742 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2743 char *data_offset;
2744 int name_len;
2745 int name_len_target;
2746 int rc = 0;
2747 int bytes_returned = 0;
2748 __u16 params, param_offset, offset, byte_count;
2749
Joe Perchesb6b38f72010-04-21 03:50:45 +00002750 cFYI(1, "In Symlink Unix style");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002751createSymLinkRetry:
2752 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2753 (void **) &pSMBr);
2754 if (rc)
2755 return rc;
2756
2757 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2758 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06002759 cifs_strtoUTF16((__le16 *) pSMB->FileName, fromName,
2760 /* find define for this maxpathcomponent */
2761 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002762 name_len++; /* trailing null */
2763 name_len *= 2;
2764
Steve French50c2f752007-07-13 00:33:32 +00002765 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002766 name_len = strnlen(fromName, PATH_MAX);
2767 name_len++; /* trailing null */
2768 strncpy(pSMB->FileName, fromName, name_len);
2769 }
2770 params = 6 + name_len;
2771 pSMB->MaxSetupCount = 0;
2772 pSMB->Reserved = 0;
2773 pSMB->Flags = 0;
2774 pSMB->Timeout = 0;
2775 pSMB->Reserved2 = 0;
2776 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002777 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002778 offset = param_offset + params;
2779
2780 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2781 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2782 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06002783 cifs_strtoUTF16((__le16 *) data_offset, toName, PATH_MAX
2784 /* find define for this maxpathcomponent */
2785 , nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002786 name_len_target++; /* trailing null */
2787 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002788 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002789 name_len_target = strnlen(toName, PATH_MAX);
2790 name_len_target++; /* trailing null */
2791 strncpy(data_offset, toName, name_len_target);
2792 }
2793
2794 pSMB->MaxParameterCount = cpu_to_le16(2);
2795 /* BB find exact max on data count below from sess */
2796 pSMB->MaxDataCount = cpu_to_le16(1000);
2797 pSMB->SetupCount = 1;
2798 pSMB->Reserved3 = 0;
2799 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2800 byte_count = 3 /* pad */ + params + name_len_target;
2801 pSMB->DataCount = cpu_to_le16(name_len_target);
2802 pSMB->ParameterCount = cpu_to_le16(params);
2803 pSMB->TotalDataCount = pSMB->DataCount;
2804 pSMB->TotalParameterCount = pSMB->ParameterCount;
2805 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2806 pSMB->DataOffset = cpu_to_le16(offset);
2807 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2808 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002809 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002810 pSMB->ByteCount = cpu_to_le16(byte_count);
2811 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2812 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002813 cifs_stats_inc(&tcon->stats.cifs_stats.num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002814 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002815 cFYI(1, "Send error in SetPathInfo create symlink = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002816
Steve French0d817bc2008-05-22 02:02:03 +00002817 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002818
2819 if (rc == -EAGAIN)
2820 goto createSymLinkRetry;
2821
2822 return rc;
2823}
2824
2825int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002826CIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002827 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002828 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002829{
2830 TRANSACTION2_SPI_REQ *pSMB = NULL;
2831 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2832 char *data_offset;
2833 int name_len;
2834 int name_len_target;
2835 int rc = 0;
2836 int bytes_returned = 0;
2837 __u16 params, param_offset, offset, byte_count;
2838
Joe Perchesb6b38f72010-04-21 03:50:45 +00002839 cFYI(1, "In Create Hard link Unix style");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002840createHardLinkRetry:
2841 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2842 (void **) &pSMBr);
2843 if (rc)
2844 return rc;
2845
2846 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002847 name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, toName,
2848 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002849 name_len++; /* trailing null */
2850 name_len *= 2;
2851
Steve French50c2f752007-07-13 00:33:32 +00002852 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002853 name_len = strnlen(toName, PATH_MAX);
2854 name_len++; /* trailing null */
2855 strncpy(pSMB->FileName, toName, name_len);
2856 }
2857 params = 6 + name_len;
2858 pSMB->MaxSetupCount = 0;
2859 pSMB->Reserved = 0;
2860 pSMB->Flags = 0;
2861 pSMB->Timeout = 0;
2862 pSMB->Reserved2 = 0;
2863 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002864 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002865 offset = param_offset + params;
2866
2867 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2868 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2869 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06002870 cifsConvertToUTF16((__le16 *) data_offset, fromName,
2871 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002872 name_len_target++; /* trailing null */
2873 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002874 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002875 name_len_target = strnlen(fromName, PATH_MAX);
2876 name_len_target++; /* trailing null */
2877 strncpy(data_offset, fromName, name_len_target);
2878 }
2879
2880 pSMB->MaxParameterCount = cpu_to_le16(2);
2881 /* BB find exact max on data count below from sess*/
2882 pSMB->MaxDataCount = cpu_to_le16(1000);
2883 pSMB->SetupCount = 1;
2884 pSMB->Reserved3 = 0;
2885 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2886 byte_count = 3 /* pad */ + params + name_len_target;
2887 pSMB->ParameterCount = cpu_to_le16(params);
2888 pSMB->TotalParameterCount = pSMB->ParameterCount;
2889 pSMB->DataCount = cpu_to_le16(name_len_target);
2890 pSMB->TotalDataCount = pSMB->DataCount;
2891 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2892 pSMB->DataOffset = cpu_to_le16(offset);
2893 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2894 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002895 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002896 pSMB->ByteCount = cpu_to_le16(byte_count);
2897 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2898 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002899 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002900 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002901 cFYI(1, "Send error in SetPathInfo (hard link) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002902
2903 cifs_buf_release(pSMB);
2904 if (rc == -EAGAIN)
2905 goto createHardLinkRetry;
2906
2907 return rc;
2908}
2909
2910int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002911CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchd6e906f2012-09-18 16:20:31 -07002912 const char *from_name, const char *to_name,
2913 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002914{
2915 int rc = 0;
2916 NT_RENAME_REQ *pSMB = NULL;
2917 RENAME_RSP *pSMBr = NULL;
2918 int bytes_returned;
2919 int name_len, name_len2;
2920 __u16 count;
Steve Frenchd6e906f2012-09-18 16:20:31 -07002921 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002922
Joe Perchesb6b38f72010-04-21 03:50:45 +00002923 cFYI(1, "In CIFSCreateHardLink");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002924winCreateHardLinkRetry:
2925
2926 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2927 (void **) &pSMBr);
2928 if (rc)
2929 return rc;
2930
2931 pSMB->SearchAttributes =
2932 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2933 ATTR_DIRECTORY);
2934 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2935 pSMB->ClusterCount = 0;
2936
2937 pSMB->BufferFormat = 0x04;
2938
2939 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2940 name_len =
Steve Frenchd6e906f2012-09-18 16:20:31 -07002941 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, from_name,
2942 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002943 name_len++; /* trailing null */
2944 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05002945
2946 /* protocol specifies ASCII buffer format (0x04) for unicode */
2947 pSMB->OldFileName[name_len] = 0x04;
2948 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002949 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002950 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Steve Frenchd6e906f2012-09-18 16:20:31 -07002951 to_name, PATH_MAX, cifs_sb->local_nls,
2952 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002953 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2954 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002955 } else { /* BB improve the check for buffer overruns BB */
Steve Frenchd6e906f2012-09-18 16:20:31 -07002956 name_len = strnlen(from_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002957 name_len++; /* trailing null */
Steve Frenchd6e906f2012-09-18 16:20:31 -07002958 strncpy(pSMB->OldFileName, from_name, name_len);
2959 name_len2 = strnlen(to_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002960 name_len2++; /* trailing null */
2961 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Steve Frenchd6e906f2012-09-18 16:20:31 -07002962 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002963 name_len2++; /* trailing null */
2964 name_len2++; /* signature byte */
2965 }
2966
2967 count = 1 /* string type byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002968 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002969 pSMB->ByteCount = cpu_to_le16(count);
2970
2971 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2972 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002973 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002974 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002975 cFYI(1, "Send error in hard link (NT rename) = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00002976
Linus Torvalds1da177e2005-04-16 15:20:36 -07002977 cifs_buf_release(pSMB);
2978 if (rc == -EAGAIN)
2979 goto winCreateHardLinkRetry;
2980
2981 return rc;
2982}
2983
2984int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002985CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04002986 const unsigned char *searchName, char **symlinkinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002987 const struct nls_table *nls_codepage)
2988{
2989/* SMB_QUERY_FILE_UNIX_LINK */
2990 TRANSACTION2_QPI_REQ *pSMB = NULL;
2991 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2992 int rc = 0;
2993 int bytes_returned;
2994 int name_len;
2995 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04002996 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002997
Joe Perchesb6b38f72010-04-21 03:50:45 +00002998 cFYI(1, "In QPathSymLinkInfo (Unix) for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002999
3000querySymLinkRetry:
3001 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3002 (void **) &pSMBr);
3003 if (rc)
3004 return rc;
3005
3006 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3007 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003008 cifs_strtoUTF16((__le16 *) pSMB->FileName, searchName,
3009 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003010 name_len++; /* trailing null */
3011 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003012 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003013 name_len = strnlen(searchName, PATH_MAX);
3014 name_len++; /* trailing null */
3015 strncpy(pSMB->FileName, searchName, name_len);
3016 }
3017
3018 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3019 pSMB->TotalDataCount = 0;
3020 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04003021 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003022 pSMB->MaxSetupCount = 0;
3023 pSMB->Reserved = 0;
3024 pSMB->Flags = 0;
3025 pSMB->Timeout = 0;
3026 pSMB->Reserved2 = 0;
3027 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003028 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003029 pSMB->DataCount = 0;
3030 pSMB->DataOffset = 0;
3031 pSMB->SetupCount = 1;
3032 pSMB->Reserved3 = 0;
3033 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3034 byte_count = params + 1 /* pad */ ;
3035 pSMB->TotalParameterCount = cpu_to_le16(params);
3036 pSMB->ParameterCount = pSMB->TotalParameterCount;
3037 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
3038 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003039 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003040 pSMB->ByteCount = cpu_to_le16(byte_count);
3041
3042 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3043 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3044 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003045 cFYI(1, "Send error in QuerySymLinkInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003046 } else {
3047 /* decode response */
3048
3049 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003050 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003051 if (rc || get_bcc(&pSMBr->hdr) < 2)
Jeff Layton460b9692009-04-30 07:17:56 -04003052 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003053 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00003054 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04003055 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003056
Jeff Layton460b9692009-04-30 07:17:56 -04003057 data_start = ((char *) &pSMBr->hdr.Protocol) +
3058 le16_to_cpu(pSMBr->t2.DataOffset);
3059
Steve French0e0d2cf2009-05-01 05:27:32 +00003060 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3061 is_unicode = true;
3062 else
3063 is_unicode = false;
3064
Steve French737b7582005-04-28 22:41:06 -07003065 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchacbbb762012-01-18 22:32:33 -06003066 *symlinkinfo = cifs_strndup_from_utf16(data_start,
3067 count, is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04003068 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04003069 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003070 }
3071 }
3072 cifs_buf_release(pSMB);
3073 if (rc == -EAGAIN)
3074 goto querySymLinkRetry;
3075 return rc;
3076}
3077
Steve Frenchc52a9552011-02-24 06:16:22 +00003078#ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL
3079/*
3080 * Recent Windows versions now create symlinks more frequently
3081 * and they use the "reparse point" mechanism below. We can of course
3082 * do symlinks nicely to Samba and other servers which support the
3083 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
3084 * "MF" symlinks optionally, but for recent Windows we really need to
3085 * reenable the code below and fix the cifs_symlink callers to handle this.
3086 * In the interim this code has been moved to its own config option so
3087 * it is not compiled in by default until callers fixed up and more tested.
3088 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003089int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003090CIFSSMBQueryReparseLinkInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003091 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00003092 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003093 const struct nls_table *nls_codepage)
3094{
3095 int rc = 0;
3096 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00003097 struct smb_com_transaction_ioctl_req *pSMB;
3098 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003099
Joe Perchesb6b38f72010-04-21 03:50:45 +00003100 cFYI(1, "In Windows reparse style QueryLink for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003101 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3102 (void **) &pSMBr);
3103 if (rc)
3104 return rc;
3105
3106 pSMB->TotalParameterCount = 0 ;
3107 pSMB->TotalDataCount = 0;
3108 pSMB->MaxParameterCount = cpu_to_le32(2);
3109 /* BB find exact data count max from sess structure BB */
Jeff Laytonc974bef2011-10-11 06:41:32 -04003110 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003111 pSMB->MaxSetupCount = 4;
3112 pSMB->Reserved = 0;
3113 pSMB->ParameterOffset = 0;
3114 pSMB->DataCount = 0;
3115 pSMB->DataOffset = 0;
3116 pSMB->SetupCount = 4;
3117 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
3118 pSMB->ParameterCount = pSMB->TotalParameterCount;
3119 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
3120 pSMB->IsFsctl = 1; /* FSCTL */
3121 pSMB->IsRootFlag = 0;
3122 pSMB->Fid = fid; /* file handle always le */
3123 pSMB->ByteCount = 0;
3124
3125 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3126 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3127 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003128 cFYI(1, "Send error in QueryReparseLinkInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003129 } else { /* decode response */
3130 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
3131 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
Jeff Layton820a8032011-05-04 08:05:26 -04003132 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
3133 /* BB also check enough total bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003134 rc = -EIO; /* bad smb */
Steve Frenchafe48c32009-05-02 05:25:46 +00003135 goto qreparse_out;
3136 }
3137 if (data_count && (data_count < 2048)) {
3138 char *end_of_smb = 2 /* sizeof byte count */ +
Jeff Layton820a8032011-05-04 08:05:26 -04003139 get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003140
Steve Frenchafe48c32009-05-02 05:25:46 +00003141 struct reparse_data *reparse_buf =
Steve French50c2f752007-07-13 00:33:32 +00003142 (struct reparse_data *)
3143 ((char *)&pSMBr->hdr.Protocol
3144 + data_offset);
Steve Frenchafe48c32009-05-02 05:25:46 +00003145 if ((char *)reparse_buf >= end_of_smb) {
3146 rc = -EIO;
3147 goto qreparse_out;
3148 }
3149 if ((reparse_buf->LinkNamesBuf +
3150 reparse_buf->TargetNameOffset +
3151 reparse_buf->TargetNameLen) > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003152 cFYI(1, "reparse buf beyond SMB");
Steve Frenchafe48c32009-05-02 05:25:46 +00003153 rc = -EIO;
3154 goto qreparse_out;
3155 }
Steve French50c2f752007-07-13 00:33:32 +00003156
Steve Frenchafe48c32009-05-02 05:25:46 +00003157 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3158 cifs_from_ucs2(symlinkinfo, (__le16 *)
Steve French50c2f752007-07-13 00:33:32 +00003159 (reparse_buf->LinkNamesBuf +
3160 reparse_buf->TargetNameOffset),
Steve Frenchafe48c32009-05-02 05:25:46 +00003161 buflen,
3162 reparse_buf->TargetNameLen,
3163 nls_codepage, 0);
3164 } else { /* ASCII names */
3165 strncpy(symlinkinfo,
3166 reparse_buf->LinkNamesBuf +
3167 reparse_buf->TargetNameOffset,
3168 min_t(const int, buflen,
3169 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003170 }
Steve Frenchafe48c32009-05-02 05:25:46 +00003171 } else {
3172 rc = -EIO;
Joe Perchesb6b38f72010-04-21 03:50:45 +00003173 cFYI(1, "Invalid return data count on "
3174 "get reparse info ioctl");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003175 }
Steve Frenchafe48c32009-05-02 05:25:46 +00003176 symlinkinfo[buflen] = 0; /* just in case so the caller
3177 does not go off the end of the buffer */
Joe Perchesb6b38f72010-04-21 03:50:45 +00003178 cFYI(1, "readlink result - %s", symlinkinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003179 }
Steve French989c7e52009-05-02 05:32:20 +00003180
Linus Torvalds1da177e2005-04-16 15:20:36 -07003181qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07003182 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003183
3184 /* Note: On -EAGAIN error only caller can retry on handle based calls
3185 since file handle passed in no longer valid */
3186
3187 return rc;
3188}
Steve Frenchc52a9552011-02-24 06:16:22 +00003189#endif /* CIFS_SYMLINK_EXPERIMENTAL */ /* BB temporarily unused */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003190
3191#ifdef CONFIG_CIFS_POSIX
3192
3193/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00003194static void cifs_convert_ace(posix_acl_xattr_entry *ace,
3195 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003196{
3197 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08003198 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
3199 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
3200 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesb6b38f72010-04-21 03:50:45 +00003201 /* cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003202
3203 return;
3204}
3205
3206/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00003207static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
3208 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003209{
3210 int size = 0;
3211 int i;
3212 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00003213 struct cifs_posix_ace *pACE;
3214 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
3215 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003216
3217 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
3218 return -EOPNOTSUPP;
3219
Steve French790fe572007-07-07 19:25:05 +00003220 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003221 count = le16_to_cpu(cifs_acl->access_entry_count);
3222 pACE = &cifs_acl->ace_array[0];
3223 size = sizeof(struct cifs_posix_acl);
3224 size += sizeof(struct cifs_posix_ace) * count;
3225 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003226 if (size_of_data_area < size) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003227 cFYI(1, "bad CIFS POSIX ACL size %d vs. %d",
3228 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003229 return -EINVAL;
3230 }
Steve French790fe572007-07-07 19:25:05 +00003231 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003232 count = le16_to_cpu(cifs_acl->access_entry_count);
3233 size = sizeof(struct cifs_posix_acl);
3234 size += sizeof(struct cifs_posix_ace) * count;
3235/* skip past access ACEs to get to default ACEs */
3236 pACE = &cifs_acl->ace_array[count];
3237 count = le16_to_cpu(cifs_acl->default_entry_count);
3238 size += sizeof(struct cifs_posix_ace) * count;
3239 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003240 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003241 return -EINVAL;
3242 } else {
3243 /* illegal type */
3244 return -EINVAL;
3245 }
3246
3247 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00003248 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00003249 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00003250 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003251 return -ERANGE;
3252 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08003253 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00003254 for (i = 0; i < count ; i++) {
3255 cifs_convert_ace(&local_acl->a_entries[i], pACE);
3256 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003257 }
3258 }
3259 return size;
3260}
3261
Steve French50c2f752007-07-13 00:33:32 +00003262static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
3263 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003264{
3265 __u16 rc = 0; /* 0 = ACL converted ok */
3266
Steve Frenchff7feac2005-11-15 16:45:16 -08003267 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
3268 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003269 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00003270 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003271 /* Probably no need to le convert -1 on any arch but can not hurt */
3272 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00003273 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08003274 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesb6b38f72010-04-21 03:50:45 +00003275 /*cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id);*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003276 return rc;
3277}
3278
3279/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00003280static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
3281 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003282{
3283 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00003284 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
3285 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003286 int count;
3287 int i;
3288
Steve French790fe572007-07-07 19:25:05 +00003289 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003290 return 0;
3291
3292 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesb6b38f72010-04-21 03:50:45 +00003293 cFYI(1, "setting acl with %d entries from buf of length %d and "
Steve French63135e02007-07-17 17:34:02 +00003294 "version of %d",
Joe Perchesb6b38f72010-04-21 03:50:45 +00003295 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00003296 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003297 cFYI(1, "unknown POSIX ACL version %d",
3298 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003299 return 0;
3300 }
3301 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00003302 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08003303 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00003304 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08003305 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003306 else {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003307 cFYI(1, "unknown ACL type %d", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003308 return 0;
3309 }
Steve French50c2f752007-07-13 00:33:32 +00003310 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003311 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
3312 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00003313 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003314 /* ACE not converted */
3315 break;
3316 }
3317 }
Steve French790fe572007-07-07 19:25:05 +00003318 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003319 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
3320 rc += sizeof(struct cifs_posix_acl);
3321 /* BB add check to make sure ACL does not overflow SMB */
3322 }
3323 return rc;
3324}
3325
3326int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003327CIFSSMBGetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003328 const unsigned char *searchName,
3329 char *acl_inf, const int buflen, const int acl_type,
3330 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003331{
3332/* SMB_QUERY_POSIX_ACL */
3333 TRANSACTION2_QPI_REQ *pSMB = NULL;
3334 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3335 int rc = 0;
3336 int bytes_returned;
3337 int name_len;
3338 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00003339
Joe Perchesb6b38f72010-04-21 03:50:45 +00003340 cFYI(1, "In GetPosixACL (Unix) for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003341
3342queryAclRetry:
3343 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3344 (void **) &pSMBr);
3345 if (rc)
3346 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003347
Linus Torvalds1da177e2005-04-16 15:20:36 -07003348 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3349 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003350 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3351 searchName, PATH_MAX, nls_codepage,
3352 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003353 name_len++; /* trailing null */
3354 name_len *= 2;
3355 pSMB->FileName[name_len] = 0;
3356 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00003357 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003358 name_len = strnlen(searchName, PATH_MAX);
3359 name_len++; /* trailing null */
3360 strncpy(pSMB->FileName, searchName, name_len);
3361 }
3362
3363 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3364 pSMB->TotalDataCount = 0;
3365 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00003366 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003367 pSMB->MaxDataCount = cpu_to_le16(4000);
3368 pSMB->MaxSetupCount = 0;
3369 pSMB->Reserved = 0;
3370 pSMB->Flags = 0;
3371 pSMB->Timeout = 0;
3372 pSMB->Reserved2 = 0;
3373 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003374 offsetof(struct smb_com_transaction2_qpi_req,
3375 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003376 pSMB->DataCount = 0;
3377 pSMB->DataOffset = 0;
3378 pSMB->SetupCount = 1;
3379 pSMB->Reserved3 = 0;
3380 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3381 byte_count = params + 1 /* pad */ ;
3382 pSMB->TotalParameterCount = cpu_to_le16(params);
3383 pSMB->ParameterCount = pSMB->TotalParameterCount;
3384 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
3385 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003386 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003387 pSMB->ByteCount = cpu_to_le16(byte_count);
3388
3389 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3390 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003391 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003392 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003393 cFYI(1, "Send error in Query POSIX ACL = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003394 } else {
3395 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00003396
Linus Torvalds1da177e2005-04-16 15:20:36 -07003397 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003398 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003399 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003400 rc = -EIO; /* bad smb */
3401 else {
3402 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3403 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3404 rc = cifs_copy_posix_acl(acl_inf,
3405 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00003406 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003407 }
3408 }
3409 cifs_buf_release(pSMB);
3410 if (rc == -EAGAIN)
3411 goto queryAclRetry;
3412 return rc;
3413}
3414
3415int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003416CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003417 const unsigned char *fileName,
3418 const char *local_acl, const int buflen,
3419 const int acl_type,
3420 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003421{
3422 struct smb_com_transaction2_spi_req *pSMB = NULL;
3423 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3424 char *parm_data;
3425 int name_len;
3426 int rc = 0;
3427 int bytes_returned = 0;
3428 __u16 params, byte_count, data_count, param_offset, offset;
3429
Joe Perchesb6b38f72010-04-21 03:50:45 +00003430 cFYI(1, "In SetPosixACL (Unix) for path %s", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003431setAclRetry:
3432 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003433 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003434 if (rc)
3435 return rc;
3436 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3437 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003438 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
3439 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003440 name_len++; /* trailing null */
3441 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003442 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003443 name_len = strnlen(fileName, PATH_MAX);
3444 name_len++; /* trailing null */
3445 strncpy(pSMB->FileName, fileName, name_len);
3446 }
3447 params = 6 + name_len;
3448 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003449 /* BB find max SMB size from sess */
3450 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003451 pSMB->MaxSetupCount = 0;
3452 pSMB->Reserved = 0;
3453 pSMB->Flags = 0;
3454 pSMB->Timeout = 0;
3455 pSMB->Reserved2 = 0;
3456 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003457 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003458 offset = param_offset + params;
3459 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
3460 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3461
3462 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00003463 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003464
Steve French790fe572007-07-07 19:25:05 +00003465 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003466 rc = -EOPNOTSUPP;
3467 goto setACLerrorExit;
3468 }
3469 pSMB->DataOffset = cpu_to_le16(offset);
3470 pSMB->SetupCount = 1;
3471 pSMB->Reserved3 = 0;
3472 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3473 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
3474 byte_count = 3 /* pad */ + params + data_count;
3475 pSMB->DataCount = cpu_to_le16(data_count);
3476 pSMB->TotalDataCount = pSMB->DataCount;
3477 pSMB->ParameterCount = cpu_to_le16(params);
3478 pSMB->TotalParameterCount = pSMB->ParameterCount;
3479 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003480 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003481 pSMB->ByteCount = cpu_to_le16(byte_count);
3482 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003483 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003484 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003485 cFYI(1, "Set POSIX ACL returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003486
3487setACLerrorExit:
3488 cifs_buf_release(pSMB);
3489 if (rc == -EAGAIN)
3490 goto setAclRetry;
3491 return rc;
3492}
3493
Steve Frenchf654bac2005-04-28 22:41:04 -07003494/* BB fix tabs in this function FIXME BB */
3495int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003496CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00003497 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07003498{
Steve French50c2f752007-07-13 00:33:32 +00003499 int rc = 0;
3500 struct smb_t2_qfi_req *pSMB = NULL;
3501 struct smb_t2_qfi_rsp *pSMBr = NULL;
3502 int bytes_returned;
3503 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07003504
Joe Perchesb6b38f72010-04-21 03:50:45 +00003505 cFYI(1, "In GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00003506 if (tcon == NULL)
3507 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07003508
3509GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003510 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3511 (void **) &pSMBr);
3512 if (rc)
3513 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003514
Steve Frenchad7a2922008-02-07 23:25:02 +00003515 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003516 pSMB->t2.TotalDataCount = 0;
3517 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3518 /* BB find exact max data count below from sess structure BB */
3519 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3520 pSMB->t2.MaxSetupCount = 0;
3521 pSMB->t2.Reserved = 0;
3522 pSMB->t2.Flags = 0;
3523 pSMB->t2.Timeout = 0;
3524 pSMB->t2.Reserved2 = 0;
3525 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3526 Fid) - 4);
3527 pSMB->t2.DataCount = 0;
3528 pSMB->t2.DataOffset = 0;
3529 pSMB->t2.SetupCount = 1;
3530 pSMB->t2.Reserved3 = 0;
3531 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3532 byte_count = params + 1 /* pad */ ;
3533 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3534 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3535 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3536 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003537 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003538 inc_rfc1001_len(pSMB, byte_count);
Steve French790fe572007-07-07 19:25:05 +00003539 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003540
Steve French790fe572007-07-07 19:25:05 +00003541 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3542 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3543 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003544 cFYI(1, "error %d in GetExtAttr", rc);
Steve French790fe572007-07-07 19:25:05 +00003545 } else {
3546 /* decode response */
3547 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003548 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003549 if (rc || get_bcc(&pSMBr->hdr) < 2)
Steve French790fe572007-07-07 19:25:05 +00003550 /* If rc should we check for EOPNOSUPP and
3551 disable the srvino flag? or in caller? */
3552 rc = -EIO; /* bad smb */
3553 else {
3554 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3555 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3556 struct file_chattr_info *pfinfo;
3557 /* BB Do we need a cast or hash here ? */
3558 if (count != 16) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003559 cFYI(1, "Illegal size ret in GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00003560 rc = -EIO;
3561 goto GetExtAttrOut;
3562 }
3563 pfinfo = (struct file_chattr_info *)
3564 (data_offset + (char *) &pSMBr->hdr.Protocol);
3565 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003566 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003567 }
3568 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003569GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003570 cifs_buf_release(pSMB);
3571 if (rc == -EAGAIN)
3572 goto GetExtAttrRetry;
3573 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003574}
3575
Steve Frenchf654bac2005-04-28 22:41:04 -07003576#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003577
Jeff Layton79df1ba2010-12-06 12:52:08 -05003578#ifdef CONFIG_CIFS_ACL
3579/*
3580 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3581 * all NT TRANSACTS that we init here have total parm and data under about 400
3582 * bytes (to fit in small cifs buffer size), which is the case so far, it
3583 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3584 * returned setup area) and MaxParameterCount (returned parms size) must be set
3585 * by caller
3586 */
3587static int
3588smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French96daf2b2011-05-27 04:34:02 +00003589 const int parm_len, struct cifs_tcon *tcon,
Jeff Layton79df1ba2010-12-06 12:52:08 -05003590 void **ret_buf)
3591{
3592 int rc;
3593 __u32 temp_offset;
3594 struct smb_com_ntransact_req *pSMB;
3595
3596 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3597 (void **)&pSMB);
3598 if (rc)
3599 return rc;
3600 *ret_buf = (void *)pSMB;
3601 pSMB->Reserved = 0;
3602 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3603 pSMB->TotalDataCount = 0;
Jeff Laytonc974bef2011-10-11 06:41:32 -04003604 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003605 pSMB->ParameterCount = pSMB->TotalParameterCount;
3606 pSMB->DataCount = pSMB->TotalDataCount;
3607 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3608 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3609 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3610 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3611 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3612 pSMB->SubCommand = cpu_to_le16(sub_command);
3613 return 0;
3614}
3615
3616static int
3617validate_ntransact(char *buf, char **ppparm, char **ppdata,
3618 __u32 *pparmlen, __u32 *pdatalen)
3619{
3620 char *end_of_smb;
3621 __u32 data_count, data_offset, parm_count, parm_offset;
3622 struct smb_com_ntransact_rsp *pSMBr;
Jeff Layton820a8032011-05-04 08:05:26 -04003623 u16 bcc;
Jeff Layton79df1ba2010-12-06 12:52:08 -05003624
3625 *pdatalen = 0;
3626 *pparmlen = 0;
3627
3628 if (buf == NULL)
3629 return -EINVAL;
3630
3631 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3632
Jeff Layton820a8032011-05-04 08:05:26 -04003633 bcc = get_bcc(&pSMBr->hdr);
3634 end_of_smb = 2 /* sizeof byte count */ + bcc +
Jeff Layton79df1ba2010-12-06 12:52:08 -05003635 (char *)&pSMBr->ByteCount;
3636
3637 data_offset = le32_to_cpu(pSMBr->DataOffset);
3638 data_count = le32_to_cpu(pSMBr->DataCount);
3639 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3640 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3641
3642 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3643 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3644
3645 /* should we also check that parm and data areas do not overlap? */
3646 if (*ppparm > end_of_smb) {
3647 cFYI(1, "parms start after end of smb");
3648 return -EINVAL;
3649 } else if (parm_count + *ppparm > end_of_smb) {
3650 cFYI(1, "parm end after end of smb");
3651 return -EINVAL;
3652 } else if (*ppdata > end_of_smb) {
3653 cFYI(1, "data starts after end of smb");
3654 return -EINVAL;
3655 } else if (data_count + *ppdata > end_of_smb) {
3656 cFYI(1, "data %p + count %d (%p) past smb end %p start %p",
3657 *ppdata, data_count, (data_count + *ppdata),
3658 end_of_smb, pSMBr);
3659 return -EINVAL;
Jeff Layton820a8032011-05-04 08:05:26 -04003660 } else if (parm_count + data_count > bcc) {
Jeff Layton79df1ba2010-12-06 12:52:08 -05003661 cFYI(1, "parm count and data count larger than SMB");
3662 return -EINVAL;
3663 }
3664 *pdatalen = data_count;
3665 *pparmlen = parm_count;
3666 return 0;
3667}
3668
Steve French0a4b92c2006-01-12 15:44:21 -08003669/* Get Security Descriptor (by handle) from remote server for a file or dir */
3670int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003671CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003672 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003673{
3674 int rc = 0;
3675 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003676 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003677 struct kvec iov[1];
3678
Joe Perchesb6b38f72010-04-21 03:50:45 +00003679 cFYI(1, "GetCifsACL");
Steve French0a4b92c2006-01-12 15:44:21 -08003680
Steve French630f3f0c2007-10-25 21:17:17 +00003681 *pbuflen = 0;
3682 *acl_inf = NULL;
3683
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003684 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003685 8 /* parm len */, tcon, (void **) &pSMB);
3686 if (rc)
3687 return rc;
3688
3689 pSMB->MaxParameterCount = cpu_to_le32(4);
3690 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3691 pSMB->MaxSetupCount = 0;
3692 pSMB->Fid = fid; /* file handle always le */
3693 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3694 CIFS_ACL_DACL);
3695 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003696 inc_rfc1001_len(pSMB, 11);
Steve French0a4b92c2006-01-12 15:44:21 -08003697 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003698 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French0a4b92c2006-01-12 15:44:21 -08003699
Steve Frencha761ac52007-10-18 21:45:27 +00003700 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Jeff Layton77499812011-01-11 07:24:23 -05003701 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003702 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Steve French0a4b92c2006-01-12 15:44:21 -08003703 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003704 cFYI(1, "Send error in QuerySecDesc = %d", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08003705 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003706 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003707 __u32 parm_len;
3708 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003709 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003710 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003711
3712/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003713 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003714 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003715 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003716 goto qsec_out;
3717 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3718
Joe Perchesb6b38f72010-04-21 03:50:45 +00003719 cFYI(1, "smb %p parm %p data %p", pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08003720
3721 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3722 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003723 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003724 goto qsec_out;
3725 }
3726
3727/* BB check that data area is minimum length and as big as acl_len */
3728
Steve Frenchaf6f4612007-10-16 18:40:37 +00003729 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003730 if (acl_len != *pbuflen) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003731 cERROR(1, "acl length %d does not match %d",
3732 acl_len, *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003733 if (*pbuflen > acl_len)
3734 *pbuflen = acl_len;
3735 }
Steve French0a4b92c2006-01-12 15:44:21 -08003736
Steve French630f3f0c2007-10-25 21:17:17 +00003737 /* check if buffer is big enough for the acl
3738 header followed by the smallest SID */
3739 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3740 (*pbuflen >= 64 * 1024)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003741 cERROR(1, "bad acl length %d", *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003742 rc = -EINVAL;
3743 *pbuflen = 0;
3744 } else {
Silviu-Mihai Popescuf7f7c182013-03-11 18:22:32 +02003745 *acl_inf = kmemdup(pdata, *pbuflen, GFP_KERNEL);
Steve French630f3f0c2007-10-25 21:17:17 +00003746 if (*acl_inf == NULL) {
3747 *pbuflen = 0;
3748 rc = -ENOMEM;
3749 }
Steve French630f3f0c2007-10-25 21:17:17 +00003750 }
Steve French0a4b92c2006-01-12 15:44:21 -08003751 }
3752qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003753 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003754 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003755 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003756 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003757/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003758 return rc;
3759}
Steve French97837582007-12-31 07:47:21 +00003760
3761int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003762CIFSSMBSetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003763 struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
Steve French97837582007-12-31 07:47:21 +00003764{
3765 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3766 int rc = 0;
3767 int bytes_returned = 0;
3768 SET_SEC_DESC_REQ *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003769 void *pSMBr;
Steve French97837582007-12-31 07:47:21 +00003770
3771setCifsAclRetry:
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003772 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, &pSMBr);
Steve French97837582007-12-31 07:47:21 +00003773 if (rc)
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003774 return rc;
Steve French97837582007-12-31 07:47:21 +00003775
3776 pSMB->MaxSetupCount = 0;
3777 pSMB->Reserved = 0;
3778
3779 param_count = 8;
3780 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3781 data_count = acllen;
3782 data_offset = param_offset + param_count;
3783 byte_count = 3 /* pad */ + param_count;
3784
3785 pSMB->DataCount = cpu_to_le32(data_count);
3786 pSMB->TotalDataCount = pSMB->DataCount;
3787 pSMB->MaxParameterCount = cpu_to_le32(4);
3788 pSMB->MaxDataCount = cpu_to_le32(16384);
3789 pSMB->ParameterCount = cpu_to_le32(param_count);
3790 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3791 pSMB->TotalParameterCount = pSMB->ParameterCount;
3792 pSMB->DataOffset = cpu_to_le32(data_offset);
3793 pSMB->SetupCount = 0;
3794 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3795 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3796
3797 pSMB->Fid = fid; /* file handle always le */
3798 pSMB->Reserved2 = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003799 pSMB->AclFlags = cpu_to_le32(aclflag);
Steve French97837582007-12-31 07:47:21 +00003800
3801 if (pntsd && acllen) {
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003802 memcpy((char *)pSMBr + offsetof(struct smb_hdr, Protocol) +
3803 data_offset, pntsd, acllen);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003804 inc_rfc1001_len(pSMB, byte_count + data_count);
Steve French97837582007-12-31 07:47:21 +00003805 } else
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003806 inc_rfc1001_len(pSMB, byte_count);
Steve French97837582007-12-31 07:47:21 +00003807
3808 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3809 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3810
Joe Perchesb6b38f72010-04-21 03:50:45 +00003811 cFYI(1, "SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00003812 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003813 cFYI(1, "Set CIFS ACL returned %d", rc);
Steve French97837582007-12-31 07:47:21 +00003814 cifs_buf_release(pSMB);
3815
3816 if (rc == -EAGAIN)
3817 goto setCifsAclRetry;
3818
3819 return (rc);
3820}
3821
Jeff Layton79df1ba2010-12-06 12:52:08 -05003822#endif /* CONFIG_CIFS_ACL */
Steve French0a4b92c2006-01-12 15:44:21 -08003823
Steve French6b8edfe2005-08-23 20:26:03 -07003824/* Legacy Query Path Information call for lookup to old servers such
3825 as Win9x/WinME */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003826int
3827SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon,
3828 const char *search_name, FILE_ALL_INFO *data,
3829 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003830{
Steve Frenchad7a2922008-02-07 23:25:02 +00003831 QUERY_INFORMATION_REQ *pSMB;
3832 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003833 int rc = 0;
3834 int bytes_returned;
3835 int name_len;
3836
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003837 cFYI(1, "In SMBQPath path %s", search_name);
Steve French6b8edfe2005-08-23 20:26:03 -07003838QInfRetry:
3839 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003840 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003841 if (rc)
3842 return rc;
3843
3844 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3845 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003846 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003847 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06003848 remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003849 name_len++; /* trailing null */
3850 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003851 } else {
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003852 name_len = strnlen(search_name, PATH_MAX);
Steve French6b8edfe2005-08-23 20:26:03 -07003853 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003854 strncpy(pSMB->FileName, search_name, name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07003855 }
3856 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003857 name_len++; /* account for buffer type byte */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003858 inc_rfc1001_len(pSMB, (__u16)name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07003859 pSMB->ByteCount = cpu_to_le16(name_len);
3860
3861 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003862 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003863 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003864 cFYI(1, "Send error in QueryInfo = %d", rc);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003865 } else if (data) {
Steve French1bd5bbc2006-09-28 03:35:57 +00003866 struct timespec ts;
3867 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00003868
3869 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003870 /* BB FIXME - add time zone adjustment BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003871 memset(data, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003872 ts.tv_nsec = 0;
3873 ts.tv_sec = time;
3874 /* decode time fields */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003875 data->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
3876 data->LastWriteTime = data->ChangeTime;
3877 data->LastAccessTime = 0;
3878 data->AllocationSize =
Steve French70ca7342005-09-22 16:32:06 -07003879 cpu_to_le64(le32_to_cpu(pSMBr->size));
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003880 data->EndOfFile = data->AllocationSize;
3881 data->Attributes =
Steve French70ca7342005-09-22 16:32:06 -07003882 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003883 } else
3884 rc = -EIO; /* bad buffer passed in */
3885
3886 cifs_buf_release(pSMB);
3887
3888 if (rc == -EAGAIN)
3889 goto QInfRetry;
3890
3891 return rc;
3892}
3893
Jeff Laytonbcd53572010-02-12 07:44:16 -05003894int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003895CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonbcd53572010-02-12 07:44:16 -05003896 u16 netfid, FILE_ALL_INFO *pFindData)
3897{
3898 struct smb_t2_qfi_req *pSMB = NULL;
3899 struct smb_t2_qfi_rsp *pSMBr = NULL;
3900 int rc = 0;
3901 int bytes_returned;
3902 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07003903
Jeff Laytonbcd53572010-02-12 07:44:16 -05003904QFileInfoRetry:
3905 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3906 (void **) &pSMBr);
3907 if (rc)
3908 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07003909
Jeff Laytonbcd53572010-02-12 07:44:16 -05003910 params = 2 /* level */ + 2 /* fid */;
3911 pSMB->t2.TotalDataCount = 0;
3912 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3913 /* BB find exact max data count below from sess structure BB */
3914 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3915 pSMB->t2.MaxSetupCount = 0;
3916 pSMB->t2.Reserved = 0;
3917 pSMB->t2.Flags = 0;
3918 pSMB->t2.Timeout = 0;
3919 pSMB->t2.Reserved2 = 0;
3920 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3921 Fid) - 4);
3922 pSMB->t2.DataCount = 0;
3923 pSMB->t2.DataOffset = 0;
3924 pSMB->t2.SetupCount = 1;
3925 pSMB->t2.Reserved3 = 0;
3926 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3927 byte_count = params + 1 /* pad */ ;
3928 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3929 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3930 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3931 pSMB->Pad = 0;
3932 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003933 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003934
3935 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3936 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3937 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00003938 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003939 } else { /* decode response */
3940 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3941
3942 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3943 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04003944 else if (get_bcc(&pSMBr->hdr) < 40)
Jeff Laytonbcd53572010-02-12 07:44:16 -05003945 rc = -EIO; /* bad smb */
3946 else if (pFindData) {
3947 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3948 memcpy((char *) pFindData,
3949 (char *) &pSMBr->hdr.Protocol +
3950 data_offset, sizeof(FILE_ALL_INFO));
3951 } else
3952 rc = -ENOMEM;
3953 }
3954 cifs_buf_release(pSMB);
3955 if (rc == -EAGAIN)
3956 goto QFileInfoRetry;
3957
3958 return rc;
3959}
Steve French6b8edfe2005-08-23 20:26:03 -07003960
Linus Torvalds1da177e2005-04-16 15:20:36 -07003961int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003962CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003963 const char *search_name, FILE_ALL_INFO *data,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003964 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003965 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003966{
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003967 /* level 263 SMB_QUERY_FILE_ALL_INFO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003968 TRANSACTION2_QPI_REQ *pSMB = NULL;
3969 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3970 int rc = 0;
3971 int bytes_returned;
3972 int name_len;
3973 __u16 params, byte_count;
3974
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003975 /* cFYI(1, "In QPathInfo path %s", search_name); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003976QPathInfoRetry:
3977 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3978 (void **) &pSMBr);
3979 if (rc)
3980 return rc;
3981
3982 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3983 name_len =
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003984 cifsConvertToUTF16((__le16 *) pSMB->FileName, search_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06003985 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003986 name_len++; /* trailing null */
3987 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003988 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003989 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003990 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003991 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003992 }
3993
Steve French50c2f752007-07-13 00:33:32 +00003994 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003995 pSMB->TotalDataCount = 0;
3996 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003997 /* BB find exact max SMB PDU from sess structure BB */
3998 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003999 pSMB->MaxSetupCount = 0;
4000 pSMB->Reserved = 0;
4001 pSMB->Flags = 0;
4002 pSMB->Timeout = 0;
4003 pSMB->Reserved2 = 0;
4004 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004005 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004006 pSMB->DataCount = 0;
4007 pSMB->DataOffset = 0;
4008 pSMB->SetupCount = 1;
4009 pSMB->Reserved3 = 0;
4010 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4011 byte_count = params + 1 /* pad */ ;
4012 pSMB->TotalParameterCount = cpu_to_le16(params);
4013 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00004014 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004015 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
4016 else
4017 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004018 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004019 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004020 pSMB->ByteCount = cpu_to_le16(byte_count);
4021
4022 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4023 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4024 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004025 cFYI(1, "Send error in QPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004026 } else { /* decode response */
4027 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4028
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004029 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4030 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004031 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004032 rc = -EIO; /* bad smb */
Jeff Layton820a8032011-05-04 08:05:26 -04004033 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
Steve French50c2f752007-07-13 00:33:32 +00004034 rc = -EIO; /* 24 or 26 expected but we do not read
4035 last field */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004036 else if (data) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004037 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004038 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00004039
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004040 /*
4041 * On legacy responses we do not read the last field,
4042 * EAsize, fortunately since it varies by subdialect and
4043 * also note it differs on Set vs Get, ie two bytes or 4
4044 * bytes depending but we don't care here.
4045 */
Steve Frenchad7a2922008-02-07 23:25:02 +00004046 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004047 size = sizeof(FILE_INFO_STANDARD);
4048 else
4049 size = sizeof(FILE_ALL_INFO);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004050 memcpy((char *) data, (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004051 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004052 } else
4053 rc = -ENOMEM;
4054 }
4055 cifs_buf_release(pSMB);
4056 if (rc == -EAGAIN)
4057 goto QPathInfoRetry;
4058
4059 return rc;
4060}
4061
4062int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004063CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004064 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
4065{
4066 struct smb_t2_qfi_req *pSMB = NULL;
4067 struct smb_t2_qfi_rsp *pSMBr = NULL;
4068 int rc = 0;
4069 int bytes_returned;
4070 __u16 params, byte_count;
4071
4072UnixQFileInfoRetry:
4073 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4074 (void **) &pSMBr);
4075 if (rc)
4076 return rc;
4077
4078 params = 2 /* level */ + 2 /* fid */;
4079 pSMB->t2.TotalDataCount = 0;
4080 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4081 /* BB find exact max data count below from sess structure BB */
4082 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4083 pSMB->t2.MaxSetupCount = 0;
4084 pSMB->t2.Reserved = 0;
4085 pSMB->t2.Flags = 0;
4086 pSMB->t2.Timeout = 0;
4087 pSMB->t2.Reserved2 = 0;
4088 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4089 Fid) - 4);
4090 pSMB->t2.DataCount = 0;
4091 pSMB->t2.DataOffset = 0;
4092 pSMB->t2.SetupCount = 1;
4093 pSMB->t2.Reserved3 = 0;
4094 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4095 byte_count = params + 1 /* pad */ ;
4096 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4097 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4098 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4099 pSMB->Pad = 0;
4100 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004101 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004102
4103 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4104 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4105 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00004106 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004107 } else { /* decode response */
4108 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4109
Jeff Layton820a8032011-05-04 08:05:26 -04004110 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004111 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response. "
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004112 "Unix Extensions can be disabled on mount "
Steve Frenchf19159d2010-04-21 04:12:10 +00004113 "by specifying the nosfu mount option.");
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004114 rc = -EIO; /* bad smb */
4115 } else {
4116 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4117 memcpy((char *) pFindData,
4118 (char *) &pSMBr->hdr.Protocol +
4119 data_offset,
4120 sizeof(FILE_UNIX_BASIC_INFO));
4121 }
4122 }
4123
4124 cifs_buf_release(pSMB);
4125 if (rc == -EAGAIN)
4126 goto UnixQFileInfoRetry;
4127
4128 return rc;
4129}
4130
4131int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004132CIFSSMBUnixQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004133 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00004134 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07004135 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004136{
4137/* SMB_QUERY_FILE_UNIX_BASIC */
4138 TRANSACTION2_QPI_REQ *pSMB = NULL;
4139 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4140 int rc = 0;
4141 int bytes_returned = 0;
4142 int name_len;
4143 __u16 params, byte_count;
4144
Joe Perchesb6b38f72010-04-21 03:50:45 +00004145 cFYI(1, "In QPathInfo (Unix) the path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004146UnixQPathInfoRetry:
4147 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4148 (void **) &pSMBr);
4149 if (rc)
4150 return rc;
4151
4152 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4153 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004154 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4155 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004156 name_len++; /* trailing null */
4157 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004158 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004159 name_len = strnlen(searchName, PATH_MAX);
4160 name_len++; /* trailing null */
4161 strncpy(pSMB->FileName, searchName, name_len);
4162 }
4163
Steve French50c2f752007-07-13 00:33:32 +00004164 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004165 pSMB->TotalDataCount = 0;
4166 pSMB->MaxParameterCount = cpu_to_le16(2);
4167 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00004168 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004169 pSMB->MaxSetupCount = 0;
4170 pSMB->Reserved = 0;
4171 pSMB->Flags = 0;
4172 pSMB->Timeout = 0;
4173 pSMB->Reserved2 = 0;
4174 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004175 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004176 pSMB->DataCount = 0;
4177 pSMB->DataOffset = 0;
4178 pSMB->SetupCount = 1;
4179 pSMB->Reserved3 = 0;
4180 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4181 byte_count = params + 1 /* pad */ ;
4182 pSMB->TotalParameterCount = cpu_to_le16(params);
4183 pSMB->ParameterCount = pSMB->TotalParameterCount;
4184 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4185 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004186 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004187 pSMB->ByteCount = cpu_to_le16(byte_count);
4188
4189 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4190 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4191 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004192 cFYI(1, "Send error in QPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004193 } else { /* decode response */
4194 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4195
Jeff Layton820a8032011-05-04 08:05:26 -04004196 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004197 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response. "
Steve French1e71f252007-09-20 15:30:07 +00004198 "Unix Extensions can be disabled on mount "
Joe Perchesb6b38f72010-04-21 03:50:45 +00004199 "by specifying the nosfu mount option.");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004200 rc = -EIO; /* bad smb */
4201 } else {
4202 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4203 memcpy((char *) pFindData,
4204 (char *) &pSMBr->hdr.Protocol +
4205 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00004206 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004207 }
4208 }
4209 cifs_buf_release(pSMB);
4210 if (rc == -EAGAIN)
4211 goto UnixQPathInfoRetry;
4212
4213 return rc;
4214}
4215
Linus Torvalds1da177e2005-04-16 15:20:36 -07004216/* xid, tcon, searchName and codepage are input parms, rest are returned */
4217int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004218CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004219 const char *searchName, struct cifs_sb_info *cifs_sb,
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004220 __u16 *pnetfid, __u16 search_flags,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004221 struct cifs_search_info *psrch_inf, bool msearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004222{
4223/* level 257 SMB_ */
4224 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
4225 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004226 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004227 int rc = 0;
4228 int bytes_returned = 0;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004229 int name_len, remap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004230 __u16 params, byte_count;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004231 struct nls_table *nls_codepage;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004232
Joe Perchesb6b38f72010-04-21 03:50:45 +00004233 cFYI(1, "In FindFirst for %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004234
4235findFirstRetry:
4236 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4237 (void **) &pSMBr);
4238 if (rc)
4239 return rc;
4240
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004241 nls_codepage = cifs_sb->local_nls;
4242 remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
4243
Linus Torvalds1da177e2005-04-16 15:20:36 -07004244 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4245 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004246 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4247 PATH_MAX, nls_codepage, remap);
Steve French737b7582005-04-28 22:41:06 -07004248 /* We can not add the asterik earlier in case
4249 it got remapped to 0xF03A as if it were part of the
4250 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004251 name_len *= 2;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004252 if (msearch) {
4253 pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
4254 pSMB->FileName[name_len+1] = 0;
4255 pSMB->FileName[name_len+2] = '*';
4256 pSMB->FileName[name_len+3] = 0;
4257 name_len += 4; /* now the trailing null */
4258 /* null terminate just in case */
4259 pSMB->FileName[name_len] = 0;
4260 pSMB->FileName[name_len+1] = 0;
4261 name_len += 2;
4262 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004263 } else { /* BB add check for overrun of SMB buf BB */
4264 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004265/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00004266 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004267 free buffer exit; BB */
4268 strncpy(pSMB->FileName, searchName, name_len);
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004269 if (msearch) {
4270 pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
4271 pSMB->FileName[name_len+1] = '*';
4272 pSMB->FileName[name_len+2] = 0;
4273 name_len += 3;
4274 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004275 }
4276
4277 params = 12 + name_len /* includes null */ ;
4278 pSMB->TotalDataCount = 0; /* no EAs */
4279 pSMB->MaxParameterCount = cpu_to_le16(10);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004280 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004281 pSMB->MaxSetupCount = 0;
4282 pSMB->Reserved = 0;
4283 pSMB->Flags = 0;
4284 pSMB->Timeout = 0;
4285 pSMB->Reserved2 = 0;
4286 byte_count = params + 1 /* pad */ ;
4287 pSMB->TotalParameterCount = cpu_to_le16(params);
4288 pSMB->ParameterCount = pSMB->TotalParameterCount;
4289 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00004290 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
4291 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004292 pSMB->DataCount = 0;
4293 pSMB->DataOffset = 0;
4294 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
4295 pSMB->Reserved3 = 0;
4296 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
4297 pSMB->SearchAttributes =
4298 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
4299 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00004300 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004301 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004302 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4303
4304 /* BB what should we set StorageType to? Does it matter? BB */
4305 pSMB->SearchStorageType = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004306 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004307 pSMB->ByteCount = cpu_to_le16(byte_count);
4308
4309 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4310 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004311 cifs_stats_inc(&tcon->stats.cifs_stats.num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004312
Steve French88274812006-03-09 22:21:45 +00004313 if (rc) {/* BB add logic to retry regular search if Unix search
4314 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004315 /* BB Add code to handle unsupported level rc */
Joe Perchesb6b38f72010-04-21 03:50:45 +00004316 cFYI(1, "Error in FindFirst = %d", rc);
Steve French1982c342005-08-17 12:38:22 -07004317
Steve French88274812006-03-09 22:21:45 +00004318 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004319
4320 /* BB eventually could optimize out free and realloc of buf */
4321 /* for this case */
4322 if (rc == -EAGAIN)
4323 goto findFirstRetry;
4324 } else { /* decode response */
4325 /* BB remember to free buffer if error BB */
4326 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00004327 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004328 unsigned int lnoff;
4329
Linus Torvalds1da177e2005-04-16 15:20:36 -07004330 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004331 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004332 else
Steve French4b18f2a2008-04-29 00:06:05 +00004333 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004334
4335 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004336 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00004337 psrch_inf->srch_entries_start =
4338 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004339 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004340 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
4341 le16_to_cpu(pSMBr->t2.ParameterOffset));
4342
Steve French790fe572007-07-07 19:25:05 +00004343 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004344 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004345 else
Steve French4b18f2a2008-04-29 00:06:05 +00004346 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004347
Steve French50c2f752007-07-13 00:33:32 +00004348 psrch_inf->entries_in_buffer =
4349 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00004350 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004351 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004352 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004353 if (CIFSMaxBufSize < lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004354 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00004355 psrch_inf->last_entry = NULL;
4356 return rc;
4357 }
4358
Steve French0752f152008-10-07 20:03:33 +00004359 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00004360 lnoff;
4361
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004362 if (pnetfid)
4363 *pnetfid = parms->SearchHandle;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004364 } else {
4365 cifs_buf_release(pSMB);
4366 }
4367 }
4368
4369 return rc;
4370}
4371
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004372int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
4373 __u16 searchHandle, __u16 search_flags,
4374 struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004375{
4376 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
4377 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004378 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004379 char *response_data;
4380 int rc = 0;
Jeff Layton9438fab2011-08-23 07:21:28 -04004381 int bytes_returned;
4382 unsigned int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004383 __u16 params, byte_count;
4384
Joe Perchesb6b38f72010-04-21 03:50:45 +00004385 cFYI(1, "In FindNext");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004386
Steve French4b18f2a2008-04-29 00:06:05 +00004387 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004388 return -ENOENT;
4389
4390 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4391 (void **) &pSMBr);
4392 if (rc)
4393 return rc;
4394
Steve French50c2f752007-07-13 00:33:32 +00004395 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004396 byte_count = 0;
4397 pSMB->TotalDataCount = 0; /* no EAs */
4398 pSMB->MaxParameterCount = cpu_to_le16(8);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004399 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004400 pSMB->MaxSetupCount = 0;
4401 pSMB->Reserved = 0;
4402 pSMB->Flags = 0;
4403 pSMB->Timeout = 0;
4404 pSMB->Reserved2 = 0;
4405 pSMB->ParameterOffset = cpu_to_le16(
4406 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
4407 pSMB->DataCount = 0;
4408 pSMB->DataOffset = 0;
4409 pSMB->SetupCount = 1;
4410 pSMB->Reserved3 = 0;
4411 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
4412 pSMB->SearchHandle = searchHandle; /* always kept as le */
4413 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00004414 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004415 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4416 pSMB->ResumeKey = psrch_inf->resume_key;
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004417 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004418
4419 name_len = psrch_inf->resume_name_len;
4420 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00004421 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004422 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
4423 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07004424 /* 14 byte parm len above enough for 2 byte null terminator */
4425 pSMB->ResumeFileName[name_len] = 0;
4426 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004427 } else {
4428 rc = -EINVAL;
4429 goto FNext2_err_exit;
4430 }
4431 byte_count = params + 1 /* pad */ ;
4432 pSMB->TotalParameterCount = cpu_to_le16(params);
4433 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004434 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004435 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004436
Linus Torvalds1da177e2005-04-16 15:20:36 -07004437 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4438 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004439 cifs_stats_inc(&tcon->stats.cifs_stats.num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004440 if (rc) {
4441 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00004442 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07004443 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00004444 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004445 } else
Joe Perchesb6b38f72010-04-21 03:50:45 +00004446 cFYI(1, "FindNext returned = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004447 } else { /* decode response */
4448 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00004449
Steve French790fe572007-07-07 19:25:05 +00004450 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004451 unsigned int lnoff;
4452
Linus Torvalds1da177e2005-04-16 15:20:36 -07004453 /* BB fixme add lock for file (srch_info) struct here */
4454 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004455 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004456 else
Steve French4b18f2a2008-04-29 00:06:05 +00004457 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004458 response_data = (char *) &pSMBr->hdr.Protocol +
4459 le16_to_cpu(pSMBr->t2.ParameterOffset);
4460 parms = (T2_FNEXT_RSP_PARMS *)response_data;
4461 response_data = (char *)&pSMBr->hdr.Protocol +
4462 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00004463 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00004464 cifs_small_buf_release(
4465 psrch_inf->ntwrk_buf_start);
4466 else
4467 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004468 psrch_inf->srch_entries_start = response_data;
4469 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004470 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00004471 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004472 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004473 else
Steve French4b18f2a2008-04-29 00:06:05 +00004474 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00004475 psrch_inf->entries_in_buffer =
4476 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004477 psrch_inf->index_of_last_entry +=
4478 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004479 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004480 if (CIFSMaxBufSize < lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004481 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00004482 psrch_inf->last_entry = NULL;
4483 return rc;
4484 } else
4485 psrch_inf->last_entry =
4486 psrch_inf->srch_entries_start + lnoff;
4487
Joe Perchesb6b38f72010-04-21 03:50:45 +00004488/* cFYI(1, "fnxt2 entries in buf %d index_of_last %d",
4489 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004490
4491 /* BB fixme add unlock here */
4492 }
4493
4494 }
4495
4496 /* BB On error, should we leave previous search buf (and count and
4497 last entry fields) intact or free the previous one? */
4498
4499 /* Note: On -EAGAIN error only caller can retry on handle based calls
4500 since file handle passed in no longer valid */
4501FNext2_err_exit:
4502 if (rc != 0)
4503 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004504 return rc;
4505}
4506
4507int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004508CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004509 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004510{
4511 int rc = 0;
4512 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004513
Joe Perchesb6b38f72010-04-21 03:50:45 +00004514 cFYI(1, "In CIFSSMBFindClose");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004515 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
4516
4517 /* no sense returning error if session restarted
4518 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00004519 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004520 return 0;
4521 if (rc)
4522 return rc;
4523
Linus Torvalds1da177e2005-04-16 15:20:36 -07004524 pSMB->FileID = searchHandle;
4525 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04004526 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004527 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00004528 cERROR(1, "Send error in FindClose = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00004529
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004530 cifs_stats_inc(&tcon->stats.cifs_stats.num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004531
4532 /* Since session is dead, search handle closed on server already */
4533 if (rc == -EAGAIN)
4534 rc = 0;
4535
4536 return rc;
4537}
4538
Linus Torvalds1da177e2005-04-16 15:20:36 -07004539int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004540CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004541 const char *search_name, __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00004542 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004543{
4544 int rc = 0;
4545 TRANSACTION2_QPI_REQ *pSMB = NULL;
4546 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4547 int name_len, bytes_returned;
4548 __u16 params, byte_count;
4549
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004550 cFYI(1, "In GetSrvInodeNum for %s", search_name);
Steve French790fe572007-07-07 19:25:05 +00004551 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00004552 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004553
4554GetInodeNumberRetry:
4555 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004556 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004557 if (rc)
4558 return rc;
4559
Linus Torvalds1da177e2005-04-16 15:20:36 -07004560 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4561 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004562 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004563 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004564 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004565 name_len++; /* trailing null */
4566 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004567 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004568 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004569 name_len++; /* trailing null */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004570 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004571 }
4572
4573 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4574 pSMB->TotalDataCount = 0;
4575 pSMB->MaxParameterCount = cpu_to_le16(2);
4576 /* BB find exact max data count below from sess structure BB */
4577 pSMB->MaxDataCount = cpu_to_le16(4000);
4578 pSMB->MaxSetupCount = 0;
4579 pSMB->Reserved = 0;
4580 pSMB->Flags = 0;
4581 pSMB->Timeout = 0;
4582 pSMB->Reserved2 = 0;
4583 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004584 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004585 pSMB->DataCount = 0;
4586 pSMB->DataOffset = 0;
4587 pSMB->SetupCount = 1;
4588 pSMB->Reserved3 = 0;
4589 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4590 byte_count = params + 1 /* pad */ ;
4591 pSMB->TotalParameterCount = cpu_to_le16(params);
4592 pSMB->ParameterCount = pSMB->TotalParameterCount;
4593 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4594 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004595 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004596 pSMB->ByteCount = cpu_to_le16(byte_count);
4597
4598 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4599 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4600 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004601 cFYI(1, "error %d in QueryInternalInfo", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004602 } else {
4603 /* decode response */
4604 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004605 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04004606 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004607 /* If rc should we check for EOPNOSUPP and
4608 disable the srvino flag? or in caller? */
4609 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00004610 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004611 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4612 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00004613 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004614 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00004615 if (count < 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004616 cFYI(1, "Illegal size ret in QryIntrnlInf");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004617 rc = -EIO;
4618 goto GetInodeNumOut;
4619 }
4620 pfinfo = (struct file_internal_info *)
4621 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00004622 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004623 }
4624 }
4625GetInodeNumOut:
4626 cifs_buf_release(pSMB);
4627 if (rc == -EAGAIN)
4628 goto GetInodeNumberRetry;
4629 return rc;
4630}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004631
Igor Mammedovfec45852008-05-16 13:06:30 +04004632/* parses DFS refferal V3 structure
4633 * caller is responsible for freeing target_nodes
4634 * returns:
4635 * on success - 0
4636 * on failure - errno
4637 */
4638static int
Steve Frencha1fe78f2008-05-16 18:48:38 +00004639parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
Igor Mammedovfec45852008-05-16 13:06:30 +04004640 unsigned int *num_of_nodes,
4641 struct dfs_info3_param **target_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004642 const struct nls_table *nls_codepage, int remap,
4643 const char *searchName)
Igor Mammedovfec45852008-05-16 13:06:30 +04004644{
4645 int i, rc = 0;
4646 char *data_end;
4647 bool is_unicode;
4648 struct dfs_referral_level_3 *ref;
4649
Harvey Harrison5ca33c62008-07-23 17:45:58 -07004650 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4651 is_unicode = true;
4652 else
4653 is_unicode = false;
Igor Mammedovfec45852008-05-16 13:06:30 +04004654 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
4655
4656 if (*num_of_nodes < 1) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004657 cERROR(1, "num_referrals: must be at least > 0,"
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004658 "but we get num_referrals = %d", *num_of_nodes);
Igor Mammedovfec45852008-05-16 13:06:30 +04004659 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004660 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004661 }
4662
4663 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
Al Viro1d92cfd2008-06-02 10:59:02 +01004664 if (ref->VersionNumber != cpu_to_le16(3)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004665 cERROR(1, "Referrals of V%d version are not supported,"
4666 "should be V3", le16_to_cpu(ref->VersionNumber));
Igor Mammedovfec45852008-05-16 13:06:30 +04004667 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004668 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004669 }
4670
4671 /* get the upper boundary of the resp buffer */
4672 data_end = (char *)(&(pSMBr->PathConsumed)) +
4673 le16_to_cpu(pSMBr->t2.DataCount);
4674
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004675 cFYI(1, "num_referrals: %d dfs flags: 0x%x ...",
Igor Mammedovfec45852008-05-16 13:06:30 +04004676 *num_of_nodes,
Joe Perchesb6b38f72010-04-21 03:50:45 +00004677 le32_to_cpu(pSMBr->DFSFlags));
Igor Mammedovfec45852008-05-16 13:06:30 +04004678
4679 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
4680 *num_of_nodes, GFP_KERNEL);
4681 if (*target_nodes == NULL) {
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004682 cERROR(1, "Failed to allocate buffer for target_nodes");
Igor Mammedovfec45852008-05-16 13:06:30 +04004683 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004684 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004685 }
4686
Daniel Mack3ad2f3f2010-02-03 08:01:28 +08004687 /* collect necessary data from referrals */
Igor Mammedovfec45852008-05-16 13:06:30 +04004688 for (i = 0; i < *num_of_nodes; i++) {
4689 char *temp;
4690 int max_len;
4691 struct dfs_info3_param *node = (*target_nodes)+i;
4692
Steve French0e0d2cf2009-05-01 05:27:32 +00004693 node->flags = le32_to_cpu(pSMBr->DFSFlags);
Igor Mammedov2c556082008-10-23 13:58:42 +04004694 if (is_unicode) {
Jeff Layton331c3132008-12-17 06:31:53 -05004695 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4696 GFP_KERNEL);
Steve French2920ee22009-08-31 15:27:26 +00004697 if (tmp == NULL) {
4698 rc = -ENOMEM;
4699 goto parse_DFS_referrals_exit;
4700 }
Steve Frenchacbbb762012-01-18 22:32:33 -06004701 cifsConvertToUTF16((__le16 *) tmp, searchName,
4702 PATH_MAX, nls_codepage, remap);
4703 node->path_consumed = cifs_utf16_bytes(tmp,
Jeff Layton69f801f2009-04-30 06:46:32 -04004704 le16_to_cpu(pSMBr->PathConsumed),
Igor Mammedov2c556082008-10-23 13:58:42 +04004705 nls_codepage);
4706 kfree(tmp);
4707 } else
4708 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4709
Igor Mammedovfec45852008-05-16 13:06:30 +04004710 node->server_type = le16_to_cpu(ref->ServerType);
4711 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4712
4713 /* copy DfsPath */
4714 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4715 max_len = data_end - temp;
Steve Frenchacbbb762012-01-18 22:32:33 -06004716 node->path_name = cifs_strndup_from_utf16(temp, max_len,
4717 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004718 if (!node->path_name) {
4719 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004720 goto parse_DFS_referrals_exit;
Jeff Layton066ce682009-04-30 07:16:14 -04004721 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004722
4723 /* copy link target UNC */
4724 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4725 max_len = data_end - temp;
Steve Frenchacbbb762012-01-18 22:32:33 -06004726 node->node_name = cifs_strndup_from_utf16(temp, max_len,
4727 is_unicode, nls_codepage);
Stefan Metzmacherd8f27992012-05-04 00:19:28 +02004728 if (!node->node_name) {
Jeff Laytond8e2f532009-05-14 07:46:59 -04004729 rc = -ENOMEM;
Stefan Metzmacherd8f27992012-05-04 00:19:28 +02004730 goto parse_DFS_referrals_exit;
4731 }
4732
4733 ref++;
Igor Mammedovfec45852008-05-16 13:06:30 +04004734 }
4735
Steve Frencha1fe78f2008-05-16 18:48:38 +00004736parse_DFS_referrals_exit:
Igor Mammedovfec45852008-05-16 13:06:30 +04004737 if (rc) {
4738 free_dfs_info_array(*target_nodes, *num_of_nodes);
4739 *target_nodes = NULL;
4740 *num_of_nodes = 0;
4741 }
4742 return rc;
4743}
4744
Linus Torvalds1da177e2005-04-16 15:20:36 -07004745int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004746CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004747 const char *search_name, struct dfs_info3_param **target_nodes,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004748 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004749 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004750{
4751/* TRANS2_GET_DFS_REFERRAL */
4752 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4753 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004754 int rc = 0;
4755 int bytes_returned;
4756 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004757 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004758 *num_of_nodes = 0;
4759 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004760
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004761 cFYI(1, "In GetDFSRefer the path %s", search_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004762 if (ses == NULL)
4763 return -ENODEV;
4764getDFSRetry:
4765 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4766 (void **) &pSMBr);
4767 if (rc)
4768 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004769
4770 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004771 but should never be null here anyway */
Pavel Shilovsky88257362012-05-23 14:01:59 +04004772 pSMB->hdr.Mid = get_next_mid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004773 pSMB->hdr.Tid = ses->ipc_tid;
4774 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004775 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004776 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004777 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004778 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004779
4780 if (ses->capabilities & CAP_UNICODE) {
4781 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4782 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004783 cifsConvertToUTF16((__le16 *) pSMB->RequestFileName,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004784 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004785 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004786 name_len++; /* trailing null */
4787 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004788 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004789 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004790 name_len++; /* trailing null */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004791 strncpy(pSMB->RequestFileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004792 }
4793
Steve French790fe572007-07-07 19:25:05 +00004794 if (ses->server) {
Steve French96daf2b2011-05-27 04:34:02 +00004795 if (ses->server->sec_mode &
Steve French1a4e15a2006-10-12 21:33:51 +00004796 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4797 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4798 }
4799
Steve French50c2f752007-07-13 00:33:32 +00004800 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004801
Linus Torvalds1da177e2005-04-16 15:20:36 -07004802 params = 2 /* level */ + name_len /*includes null */ ;
4803 pSMB->TotalDataCount = 0;
4804 pSMB->DataCount = 0;
4805 pSMB->DataOffset = 0;
4806 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004807 /* BB find exact max SMB PDU from sess structure BB */
4808 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004809 pSMB->MaxSetupCount = 0;
4810 pSMB->Reserved = 0;
4811 pSMB->Flags = 0;
4812 pSMB->Timeout = 0;
4813 pSMB->Reserved2 = 0;
4814 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004815 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004816 pSMB->SetupCount = 1;
4817 pSMB->Reserved3 = 0;
4818 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4819 byte_count = params + 3 /* pad */ ;
4820 pSMB->ParameterCount = cpu_to_le16(params);
4821 pSMB->TotalParameterCount = pSMB->ParameterCount;
4822 pSMB->MaxReferralLevel = cpu_to_le16(3);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004823 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004824 pSMB->ByteCount = cpu_to_le16(byte_count);
4825
4826 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4827 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4828 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004829 cFYI(1, "Send error in GetDFSRefer = %d", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004830 goto GetDFSRefExit;
4831 }
4832 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004833
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004834 /* BB Also check if enough total bytes returned? */
Jeff Layton820a8032011-05-04 08:05:26 -04004835 if (rc || get_bcc(&pSMBr->hdr) < 17) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004836 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004837 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004838 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004839
Joe Perchesb6b38f72010-04-21 03:50:45 +00004840 cFYI(1, "Decoding GetDFSRefer response BCC: %d Offset %d",
Jeff Layton820a8032011-05-04 08:05:26 -04004841 get_bcc(&pSMBr->hdr),
Joe Perchesb6b38f72010-04-21 03:50:45 +00004842 le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04004843
4844 /* parse returned result into more usable form */
Steve Frencha1fe78f2008-05-16 18:48:38 +00004845 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004846 target_nodes, nls_codepage, remap,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004847 search_name);
Igor Mammedovfec45852008-05-16 13:06:30 +04004848
Linus Torvalds1da177e2005-04-16 15:20:36 -07004849GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004850 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004851
4852 if (rc == -EAGAIN)
4853 goto getDFSRetry;
4854
4855 return rc;
4856}
4857
Steve French20962432005-09-21 22:05:57 -07004858/* Query File System Info such as free space to old servers such as Win 9x */
4859int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004860SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4861 struct kstatfs *FSData)
Steve French20962432005-09-21 22:05:57 -07004862{
4863/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4864 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4865 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4866 FILE_SYSTEM_ALLOC_INFO *response_data;
4867 int rc = 0;
4868 int bytes_returned = 0;
4869 __u16 params, byte_count;
4870
Joe Perchesb6b38f72010-04-21 03:50:45 +00004871 cFYI(1, "OldQFSInfo");
Steve French20962432005-09-21 22:05:57 -07004872oldQFSInfoRetry:
4873 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4874 (void **) &pSMBr);
4875 if (rc)
4876 return rc;
Steve French20962432005-09-21 22:05:57 -07004877
4878 params = 2; /* level */
4879 pSMB->TotalDataCount = 0;
4880 pSMB->MaxParameterCount = cpu_to_le16(2);
4881 pSMB->MaxDataCount = cpu_to_le16(1000);
4882 pSMB->MaxSetupCount = 0;
4883 pSMB->Reserved = 0;
4884 pSMB->Flags = 0;
4885 pSMB->Timeout = 0;
4886 pSMB->Reserved2 = 0;
4887 byte_count = params + 1 /* pad */ ;
4888 pSMB->TotalParameterCount = cpu_to_le16(params);
4889 pSMB->ParameterCount = pSMB->TotalParameterCount;
4890 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4891 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4892 pSMB->DataCount = 0;
4893 pSMB->DataOffset = 0;
4894 pSMB->SetupCount = 1;
4895 pSMB->Reserved3 = 0;
4896 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4897 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004898 inc_rfc1001_len(pSMB, byte_count);
Steve French20962432005-09-21 22:05:57 -07004899 pSMB->ByteCount = cpu_to_le16(byte_count);
4900
4901 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4902 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4903 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004904 cFYI(1, "Send error in QFSInfo = %d", rc);
Steve French20962432005-09-21 22:05:57 -07004905 } else { /* decode response */
4906 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4907
Jeff Layton820a8032011-05-04 08:05:26 -04004908 if (rc || get_bcc(&pSMBr->hdr) < 18)
Steve French20962432005-09-21 22:05:57 -07004909 rc = -EIO; /* bad smb */
4910 else {
4911 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004912 cFYI(1, "qfsinf resp BCC: %d Offset %d",
Jeff Layton820a8032011-05-04 08:05:26 -04004913 get_bcc(&pSMBr->hdr), data_offset);
Steve French20962432005-09-21 22:05:57 -07004914
Steve French50c2f752007-07-13 00:33:32 +00004915 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004916 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4917 FSData->f_bsize =
4918 le16_to_cpu(response_data->BytesPerSector) *
4919 le32_to_cpu(response_data->
4920 SectorsPerAllocationUnit);
4921 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004922 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004923 FSData->f_bfree = FSData->f_bavail =
4924 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004925 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
4926 (unsigned long long)FSData->f_blocks,
4927 (unsigned long long)FSData->f_bfree,
4928 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07004929 }
4930 }
4931 cifs_buf_release(pSMB);
4932
4933 if (rc == -EAGAIN)
4934 goto oldQFSInfoRetry;
4935
4936 return rc;
4937}
4938
Linus Torvalds1da177e2005-04-16 15:20:36 -07004939int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004940CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4941 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004942{
4943/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4944 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4945 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4946 FILE_SYSTEM_INFO *response_data;
4947 int rc = 0;
4948 int bytes_returned = 0;
4949 __u16 params, byte_count;
4950
Joe Perchesb6b38f72010-04-21 03:50:45 +00004951 cFYI(1, "In QFSInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004952QFSInfoRetry:
4953 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4954 (void **) &pSMBr);
4955 if (rc)
4956 return rc;
4957
4958 params = 2; /* level */
4959 pSMB->TotalDataCount = 0;
4960 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004961 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004962 pSMB->MaxSetupCount = 0;
4963 pSMB->Reserved = 0;
4964 pSMB->Flags = 0;
4965 pSMB->Timeout = 0;
4966 pSMB->Reserved2 = 0;
4967 byte_count = params + 1 /* pad */ ;
4968 pSMB->TotalParameterCount = cpu_to_le16(params);
4969 pSMB->ParameterCount = pSMB->TotalParameterCount;
4970 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004971 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004972 pSMB->DataCount = 0;
4973 pSMB->DataOffset = 0;
4974 pSMB->SetupCount = 1;
4975 pSMB->Reserved3 = 0;
4976 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4977 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004978 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004979 pSMB->ByteCount = cpu_to_le16(byte_count);
4980
4981 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4982 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4983 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004984 cFYI(1, "Send error in QFSInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004985 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00004986 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004987
Jeff Layton820a8032011-05-04 08:05:26 -04004988 if (rc || get_bcc(&pSMBr->hdr) < 24)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004989 rc = -EIO; /* bad smb */
4990 else {
4991 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004992
4993 response_data =
4994 (FILE_SYSTEM_INFO
4995 *) (((char *) &pSMBr->hdr.Protocol) +
4996 data_offset);
4997 FSData->f_bsize =
4998 le32_to_cpu(response_data->BytesPerSector) *
4999 le32_to_cpu(response_data->
5000 SectorsPerAllocationUnit);
5001 FSData->f_blocks =
5002 le64_to_cpu(response_data->TotalAllocationUnits);
5003 FSData->f_bfree = FSData->f_bavail =
5004 le64_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesb6b38f72010-04-21 03:50:45 +00005005 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
5006 (unsigned long long)FSData->f_blocks,
5007 (unsigned long long)FSData->f_bfree,
5008 FSData->f_bsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005009 }
5010 }
5011 cifs_buf_release(pSMB);
5012
5013 if (rc == -EAGAIN)
5014 goto QFSInfoRetry;
5015
5016 return rc;
5017}
5018
5019int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005020CIFSSMBQFSAttributeInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005021{
5022/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
5023 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5024 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5025 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
5026 int rc = 0;
5027 int bytes_returned = 0;
5028 __u16 params, byte_count;
5029
Joe Perchesb6b38f72010-04-21 03:50:45 +00005030 cFYI(1, "In QFSAttributeInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005031QFSAttributeRetry:
5032 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5033 (void **) &pSMBr);
5034 if (rc)
5035 return rc;
5036
5037 params = 2; /* level */
5038 pSMB->TotalDataCount = 0;
5039 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005040 /* BB find exact max SMB PDU from sess structure BB */
5041 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005042 pSMB->MaxSetupCount = 0;
5043 pSMB->Reserved = 0;
5044 pSMB->Flags = 0;
5045 pSMB->Timeout = 0;
5046 pSMB->Reserved2 = 0;
5047 byte_count = params + 1 /* pad */ ;
5048 pSMB->TotalParameterCount = cpu_to_le16(params);
5049 pSMB->ParameterCount = pSMB->TotalParameterCount;
5050 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005051 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005052 pSMB->DataCount = 0;
5053 pSMB->DataOffset = 0;
5054 pSMB->SetupCount = 1;
5055 pSMB->Reserved3 = 0;
5056 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5057 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005058 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005059 pSMB->ByteCount = cpu_to_le16(byte_count);
5060
5061 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5062 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5063 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005064 cERROR(1, "Send error in QFSAttributeInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005065 } else { /* decode response */
5066 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5067
Jeff Layton820a8032011-05-04 08:05:26 -04005068 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Steve French50c2f752007-07-13 00:33:32 +00005069 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005070 rc = -EIO; /* bad smb */
5071 } else {
5072 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5073 response_data =
5074 (FILE_SYSTEM_ATTRIBUTE_INFO
5075 *) (((char *) &pSMBr->hdr.Protocol) +
5076 data_offset);
5077 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005078 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005079 }
5080 }
5081 cifs_buf_release(pSMB);
5082
5083 if (rc == -EAGAIN)
5084 goto QFSAttributeRetry;
5085
5086 return rc;
5087}
5088
5089int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005090CIFSSMBQFSDeviceInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005091{
5092/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
5093 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5094 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5095 FILE_SYSTEM_DEVICE_INFO *response_data;
5096 int rc = 0;
5097 int bytes_returned = 0;
5098 __u16 params, byte_count;
5099
Joe Perchesb6b38f72010-04-21 03:50:45 +00005100 cFYI(1, "In QFSDeviceInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005101QFSDeviceRetry:
5102 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5103 (void **) &pSMBr);
5104 if (rc)
5105 return rc;
5106
5107 params = 2; /* level */
5108 pSMB->TotalDataCount = 0;
5109 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005110 /* BB find exact max SMB PDU from sess structure BB */
5111 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005112 pSMB->MaxSetupCount = 0;
5113 pSMB->Reserved = 0;
5114 pSMB->Flags = 0;
5115 pSMB->Timeout = 0;
5116 pSMB->Reserved2 = 0;
5117 byte_count = params + 1 /* pad */ ;
5118 pSMB->TotalParameterCount = cpu_to_le16(params);
5119 pSMB->ParameterCount = pSMB->TotalParameterCount;
5120 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005121 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005122
5123 pSMB->DataCount = 0;
5124 pSMB->DataOffset = 0;
5125 pSMB->SetupCount = 1;
5126 pSMB->Reserved3 = 0;
5127 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5128 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005129 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005130 pSMB->ByteCount = cpu_to_le16(byte_count);
5131
5132 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5133 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5134 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005135 cFYI(1, "Send error in QFSDeviceInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005136 } else { /* decode response */
5137 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5138
Jeff Layton820a8032011-05-04 08:05:26 -04005139 if (rc || get_bcc(&pSMBr->hdr) <
5140 sizeof(FILE_SYSTEM_DEVICE_INFO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005141 rc = -EIO; /* bad smb */
5142 else {
5143 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5144 response_data =
Steve French737b7582005-04-28 22:41:06 -07005145 (FILE_SYSTEM_DEVICE_INFO *)
5146 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07005147 data_offset);
5148 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005149 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005150 }
5151 }
5152 cifs_buf_release(pSMB);
5153
5154 if (rc == -EAGAIN)
5155 goto QFSDeviceRetry;
5156
5157 return rc;
5158}
5159
5160int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005161CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005162{
5163/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
5164 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5165 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5166 FILE_SYSTEM_UNIX_INFO *response_data;
5167 int rc = 0;
5168 int bytes_returned = 0;
5169 __u16 params, byte_count;
5170
Joe Perchesb6b38f72010-04-21 03:50:45 +00005171 cFYI(1, "In QFSUnixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005172QFSUnixRetry:
Jeff Laytonf5695992010-09-29 15:27:08 -04005173 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5174 (void **) &pSMB, (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005175 if (rc)
5176 return rc;
5177
5178 params = 2; /* level */
5179 pSMB->TotalDataCount = 0;
5180 pSMB->DataCount = 0;
5181 pSMB->DataOffset = 0;
5182 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005183 /* BB find exact max SMB PDU from sess structure BB */
5184 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005185 pSMB->MaxSetupCount = 0;
5186 pSMB->Reserved = 0;
5187 pSMB->Flags = 0;
5188 pSMB->Timeout = 0;
5189 pSMB->Reserved2 = 0;
5190 byte_count = params + 1 /* pad */ ;
5191 pSMB->ParameterCount = cpu_to_le16(params);
5192 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005193 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5194 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005195 pSMB->SetupCount = 1;
5196 pSMB->Reserved3 = 0;
5197 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5198 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005199 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005200 pSMB->ByteCount = cpu_to_le16(byte_count);
5201
5202 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5203 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5204 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005205 cERROR(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005206 } else { /* decode response */
5207 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5208
Jeff Layton820a8032011-05-04 08:05:26 -04005209 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005210 rc = -EIO; /* bad smb */
5211 } else {
5212 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5213 response_data =
5214 (FILE_SYSTEM_UNIX_INFO
5215 *) (((char *) &pSMBr->hdr.Protocol) +
5216 data_offset);
5217 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005218 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005219 }
5220 }
5221 cifs_buf_release(pSMB);
5222
5223 if (rc == -EAGAIN)
5224 goto QFSUnixRetry;
5225
5226
5227 return rc;
5228}
5229
Jeremy Allisonac670552005-06-22 17:26:35 -07005230int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005231CIFSSMBSetFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07005232{
5233/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
5234 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
5235 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
5236 int rc = 0;
5237 int bytes_returned = 0;
5238 __u16 params, param_offset, offset, byte_count;
5239
Joe Perchesb6b38f72010-04-21 03:50:45 +00005240 cFYI(1, "In SETFSUnixInfo");
Jeremy Allisonac670552005-06-22 17:26:35 -07005241SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00005242 /* BB switch to small buf init to save memory */
Jeff Laytonf5695992010-09-29 15:27:08 -04005243 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5244 (void **) &pSMB, (void **) &pSMBr);
Jeremy Allisonac670552005-06-22 17:26:35 -07005245 if (rc)
5246 return rc;
5247
5248 params = 4; /* 2 bytes zero followed by info level. */
5249 pSMB->MaxSetupCount = 0;
5250 pSMB->Reserved = 0;
5251 pSMB->Flags = 0;
5252 pSMB->Timeout = 0;
5253 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00005254 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
5255 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07005256 offset = param_offset + params;
5257
5258 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00005259 /* BB find exact max SMB PDU from sess structure BB */
5260 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07005261 pSMB->SetupCount = 1;
5262 pSMB->Reserved3 = 0;
5263 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
5264 byte_count = 1 /* pad */ + params + 12;
5265
5266 pSMB->DataCount = cpu_to_le16(12);
5267 pSMB->ParameterCount = cpu_to_le16(params);
5268 pSMB->TotalDataCount = pSMB->DataCount;
5269 pSMB->TotalParameterCount = pSMB->ParameterCount;
5270 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5271 pSMB->DataOffset = cpu_to_le16(offset);
5272
5273 /* Params. */
5274 pSMB->FileNum = 0;
5275 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
5276
5277 /* Data. */
5278 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
5279 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
5280 pSMB->ClientUnixCap = cpu_to_le64(cap);
5281
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005282 inc_rfc1001_len(pSMB, byte_count);
Jeremy Allisonac670552005-06-22 17:26:35 -07005283 pSMB->ByteCount = cpu_to_le16(byte_count);
5284
5285 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5286 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5287 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005288 cERROR(1, "Send error in SETFSUnixInfo = %d", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07005289 } else { /* decode response */
5290 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00005291 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07005292 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07005293 }
5294 cifs_buf_release(pSMB);
5295
5296 if (rc == -EAGAIN)
5297 goto SETFSUnixRetry;
5298
5299 return rc;
5300}
5301
5302
Linus Torvalds1da177e2005-04-16 15:20:36 -07005303
5304int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005305CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon,
Steve French737b7582005-04-28 22:41:06 -07005306 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005307{
5308/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
5309 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5310 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5311 FILE_SYSTEM_POSIX_INFO *response_data;
5312 int rc = 0;
5313 int bytes_returned = 0;
5314 __u16 params, byte_count;
5315
Joe Perchesb6b38f72010-04-21 03:50:45 +00005316 cFYI(1, "In QFSPosixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005317QFSPosixRetry:
5318 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5319 (void **) &pSMBr);
5320 if (rc)
5321 return rc;
5322
5323 params = 2; /* level */
5324 pSMB->TotalDataCount = 0;
5325 pSMB->DataCount = 0;
5326 pSMB->DataOffset = 0;
5327 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005328 /* BB find exact max SMB PDU from sess structure BB */
5329 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005330 pSMB->MaxSetupCount = 0;
5331 pSMB->Reserved = 0;
5332 pSMB->Flags = 0;
5333 pSMB->Timeout = 0;
5334 pSMB->Reserved2 = 0;
5335 byte_count = params + 1 /* pad */ ;
5336 pSMB->ParameterCount = cpu_to_le16(params);
5337 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005338 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5339 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005340 pSMB->SetupCount = 1;
5341 pSMB->Reserved3 = 0;
5342 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5343 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005344 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005345 pSMB->ByteCount = cpu_to_le16(byte_count);
5346
5347 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5348 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5349 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005350 cFYI(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005351 } else { /* decode response */
5352 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5353
Jeff Layton820a8032011-05-04 08:05:26 -04005354 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005355 rc = -EIO; /* bad smb */
5356 } else {
5357 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5358 response_data =
5359 (FILE_SYSTEM_POSIX_INFO
5360 *) (((char *) &pSMBr->hdr.Protocol) +
5361 data_offset);
5362 FSData->f_bsize =
5363 le32_to_cpu(response_data->BlockSize);
5364 FSData->f_blocks =
5365 le64_to_cpu(response_data->TotalBlocks);
5366 FSData->f_bfree =
5367 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00005368 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005369 FSData->f_bavail = FSData->f_bfree;
5370 } else {
5371 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00005372 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005373 }
Steve French790fe572007-07-07 19:25:05 +00005374 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005375 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00005376 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00005377 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005378 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00005379 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005380 }
5381 }
5382 cifs_buf_release(pSMB);
5383
5384 if (rc == -EAGAIN)
5385 goto QFSPosixRetry;
5386
5387 return rc;
5388}
5389
5390
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005391/*
5392 * We can not use write of zero bytes trick to set file size due to need for
5393 * large file support. Also note that this SetPathInfo is preferred to
5394 * SetFileInfo based method in next routine which is only needed to work around
5395 * a sharing violation bugin Samba which this routine can run into.
5396 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005397int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005398CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005399 const char *file_name, __u64 size, struct cifs_sb_info *cifs_sb,
5400 bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005401{
5402 struct smb_com_transaction2_spi_req *pSMB = NULL;
5403 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5404 struct file_end_of_file_info *parm_data;
5405 int name_len;
5406 int rc = 0;
5407 int bytes_returned = 0;
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005408 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
5409
Linus Torvalds1da177e2005-04-16 15:20:36 -07005410 __u16 params, byte_count, data_count, param_offset, offset;
5411
Joe Perchesb6b38f72010-04-21 03:50:45 +00005412 cFYI(1, "In SetEOF");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005413SetEOFRetry:
5414 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5415 (void **) &pSMBr);
5416 if (rc)
5417 return rc;
5418
5419 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5420 name_len =
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005421 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
5422 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005423 name_len++; /* trailing null */
5424 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005425 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005426 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005427 name_len++; /* trailing null */
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005428 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005429 }
5430 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005431 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005432 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07005433 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005434 pSMB->MaxSetupCount = 0;
5435 pSMB->Reserved = 0;
5436 pSMB->Flags = 0;
5437 pSMB->Timeout = 0;
5438 pSMB->Reserved2 = 0;
5439 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005440 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005441 offset = param_offset + params;
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005442 if (set_allocation) {
Steve French50c2f752007-07-13 00:33:32 +00005443 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5444 pSMB->InformationLevel =
5445 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5446 else
5447 pSMB->InformationLevel =
5448 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5449 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005450 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5451 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005452 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005453 else
5454 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005455 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005456 }
5457
5458 parm_data =
5459 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
5460 offset);
5461 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5462 pSMB->DataOffset = cpu_to_le16(offset);
5463 pSMB->SetupCount = 1;
5464 pSMB->Reserved3 = 0;
5465 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5466 byte_count = 3 /* pad */ + params + data_count;
5467 pSMB->DataCount = cpu_to_le16(data_count);
5468 pSMB->TotalDataCount = pSMB->DataCount;
5469 pSMB->ParameterCount = cpu_to_le16(params);
5470 pSMB->TotalParameterCount = pSMB->ParameterCount;
5471 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005472 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005473 parm_data->FileSize = cpu_to_le64(size);
5474 pSMB->ByteCount = cpu_to_le16(byte_count);
5475 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5476 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005477 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005478 cFYI(1, "SetPathInfo (file size) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005479
5480 cifs_buf_release(pSMB);
5481
5482 if (rc == -EAGAIN)
5483 goto SetEOFRetry;
5484
5485 return rc;
5486}
5487
5488int
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005489CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
5490 struct cifsFileInfo *cfile, __u64 size, bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005491{
5492 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005493 struct file_end_of_file_info *parm_data;
5494 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005495 __u16 params, param_offset, offset, byte_count, count;
5496
Joe Perchesb6b38f72010-04-21 03:50:45 +00005497 cFYI(1, "SetFileSize (via SetFileInfo) %lld",
5498 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07005499 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5500
Linus Torvalds1da177e2005-04-16 15:20:36 -07005501 if (rc)
5502 return rc;
5503
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005504 pSMB->hdr.Pid = cpu_to_le16((__u16)cfile->pid);
5505 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(cfile->pid >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005506
Linus Torvalds1da177e2005-04-16 15:20:36 -07005507 params = 6;
5508 pSMB->MaxSetupCount = 0;
5509 pSMB->Reserved = 0;
5510 pSMB->Flags = 0;
5511 pSMB->Timeout = 0;
5512 pSMB->Reserved2 = 0;
5513 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5514 offset = param_offset + params;
5515
Linus Torvalds1da177e2005-04-16 15:20:36 -07005516 count = sizeof(struct file_end_of_file_info);
5517 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005518 /* BB find exact max SMB PDU from sess structure BB */
5519 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005520 pSMB->SetupCount = 1;
5521 pSMB->Reserved3 = 0;
5522 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5523 byte_count = 3 /* pad */ + params + count;
5524 pSMB->DataCount = cpu_to_le16(count);
5525 pSMB->ParameterCount = cpu_to_le16(params);
5526 pSMB->TotalDataCount = pSMB->DataCount;
5527 pSMB->TotalParameterCount = pSMB->ParameterCount;
5528 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5529 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00005530 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
5531 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005532 pSMB->DataOffset = cpu_to_le16(offset);
5533 parm_data->FileSize = cpu_to_le64(size);
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005534 pSMB->Fid = cfile->fid.netfid;
5535 if (set_allocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005536 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5537 pSMB->InformationLevel =
5538 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5539 else
5540 pSMB->InformationLevel =
5541 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00005542 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005543 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5544 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005545 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005546 else
5547 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005548 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005549 }
5550 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005551 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005552 pSMB->ByteCount = cpu_to_le16(byte_count);
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005553 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005554 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005555 cFYI(1, "Send error in SetFileInfo (SetFileSize) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005556 }
5557
Steve French50c2f752007-07-13 00:33:32 +00005558 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005559 since file handle passed in no longer valid */
5560
5561 return rc;
5562}
5563
Steve French50c2f752007-07-13 00:33:32 +00005564/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07005565 an open handle, rather than by pathname - this is awkward due to
5566 potential access conflicts on the open, but it is unavoidable for these
5567 old servers since the only other choice is to go from 100 nanosecond DCE
5568 time and resort to the original setpathinfo level which takes the ancient
5569 DOS time format with 2 second granularity */
5570int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005571CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005572 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005573{
5574 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005575 char *data_offset;
5576 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005577 __u16 params, param_offset, offset, byte_count, count;
5578
Joe Perchesb6b38f72010-04-21 03:50:45 +00005579 cFYI(1, "Set Times (via SetFileInfo)");
Steve Frenchcd634992005-04-28 22:41:10 -07005580 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5581
Linus Torvalds1da177e2005-04-16 15:20:36 -07005582 if (rc)
5583 return rc;
5584
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005585 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5586 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005587
Linus Torvalds1da177e2005-04-16 15:20:36 -07005588 params = 6;
5589 pSMB->MaxSetupCount = 0;
5590 pSMB->Reserved = 0;
5591 pSMB->Flags = 0;
5592 pSMB->Timeout = 0;
5593 pSMB->Reserved2 = 0;
5594 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5595 offset = param_offset + params;
5596
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005597 data_offset = (char *)pSMB +
5598 offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005599
Steve French26f57362007-08-30 22:09:15 +00005600 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005601 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005602 /* BB find max SMB PDU from sess */
5603 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005604 pSMB->SetupCount = 1;
5605 pSMB->Reserved3 = 0;
5606 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5607 byte_count = 3 /* pad */ + params + count;
5608 pSMB->DataCount = cpu_to_le16(count);
5609 pSMB->ParameterCount = cpu_to_le16(params);
5610 pSMB->TotalDataCount = pSMB->DataCount;
5611 pSMB->TotalParameterCount = pSMB->ParameterCount;
5612 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5613 pSMB->DataOffset = cpu_to_le16(offset);
5614 pSMB->Fid = fid;
5615 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5616 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5617 else
5618 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5619 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005620 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005621 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005622 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005623 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005624 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005625 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005626
Steve French50c2f752007-07-13 00:33:32 +00005627 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005628 since file handle passed in no longer valid */
5629
5630 return rc;
5631}
5632
Jeff Layton6d22f092008-09-23 11:48:35 -04005633int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005634CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6d22f092008-09-23 11:48:35 -04005635 bool delete_file, __u16 fid, __u32 pid_of_opener)
5636{
5637 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5638 char *data_offset;
5639 int rc = 0;
5640 __u16 params, param_offset, offset, byte_count, count;
5641
Joe Perchesb6b38f72010-04-21 03:50:45 +00005642 cFYI(1, "Set File Disposition (via SetFileInfo)");
Jeff Layton6d22f092008-09-23 11:48:35 -04005643 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5644
5645 if (rc)
5646 return rc;
5647
5648 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5649 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5650
5651 params = 6;
5652 pSMB->MaxSetupCount = 0;
5653 pSMB->Reserved = 0;
5654 pSMB->Flags = 0;
5655 pSMB->Timeout = 0;
5656 pSMB->Reserved2 = 0;
5657 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5658 offset = param_offset + params;
5659
5660 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5661
5662 count = 1;
5663 pSMB->MaxParameterCount = cpu_to_le16(2);
5664 /* BB find max SMB PDU from sess */
5665 pSMB->MaxDataCount = cpu_to_le16(1000);
5666 pSMB->SetupCount = 1;
5667 pSMB->Reserved3 = 0;
5668 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5669 byte_count = 3 /* pad */ + params + count;
5670 pSMB->DataCount = cpu_to_le16(count);
5671 pSMB->ParameterCount = cpu_to_le16(params);
5672 pSMB->TotalDataCount = pSMB->DataCount;
5673 pSMB->TotalParameterCount = pSMB->ParameterCount;
5674 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5675 pSMB->DataOffset = cpu_to_le16(offset);
5676 pSMB->Fid = fid;
5677 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5678 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005679 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton6d22f092008-09-23 11:48:35 -04005680 pSMB->ByteCount = cpu_to_le16(byte_count);
5681 *data_offset = delete_file ? 1 : 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005682 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Jeff Layton6d22f092008-09-23 11:48:35 -04005683 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005684 cFYI(1, "Send error in SetFileDisposition = %d", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005685
5686 return rc;
5687}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005688
5689int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005690CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6fc000e2008-08-02 07:26:12 -04005691 const char *fileName, const FILE_BASIC_INFO *data,
5692 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005693{
5694 TRANSACTION2_SPI_REQ *pSMB = NULL;
5695 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5696 int name_len;
5697 int rc = 0;
5698 int bytes_returned = 0;
5699 char *data_offset;
5700 __u16 params, param_offset, offset, byte_count, count;
5701
Joe Perchesb6b38f72010-04-21 03:50:45 +00005702 cFYI(1, "In SetTimes");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005703
5704SetTimesRetry:
5705 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5706 (void **) &pSMBr);
5707 if (rc)
5708 return rc;
5709
5710 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5711 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005712 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5713 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005714 name_len++; /* trailing null */
5715 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005716 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005717 name_len = strnlen(fileName, PATH_MAX);
5718 name_len++; /* trailing null */
5719 strncpy(pSMB->FileName, fileName, name_len);
5720 }
5721
5722 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005723 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005724 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005725 /* BB find max SMB PDU from sess structure BB */
5726 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005727 pSMB->MaxSetupCount = 0;
5728 pSMB->Reserved = 0;
5729 pSMB->Flags = 0;
5730 pSMB->Timeout = 0;
5731 pSMB->Reserved2 = 0;
5732 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005733 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005734 offset = param_offset + params;
5735 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5736 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5737 pSMB->DataOffset = cpu_to_le16(offset);
5738 pSMB->SetupCount = 1;
5739 pSMB->Reserved3 = 0;
5740 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5741 byte_count = 3 /* pad */ + params + count;
5742
5743 pSMB->DataCount = cpu_to_le16(count);
5744 pSMB->ParameterCount = cpu_to_le16(params);
5745 pSMB->TotalDataCount = pSMB->DataCount;
5746 pSMB->TotalParameterCount = pSMB->ParameterCount;
5747 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5748 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5749 else
5750 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5751 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005752 inc_rfc1001_len(pSMB, byte_count);
Steve French26f57362007-08-30 22:09:15 +00005753 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005754 pSMB->ByteCount = cpu_to_le16(byte_count);
5755 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5756 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005757 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005758 cFYI(1, "SetPathInfo (times) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005759
5760 cifs_buf_release(pSMB);
5761
5762 if (rc == -EAGAIN)
5763 goto SetTimesRetry;
5764
5765 return rc;
5766}
5767
5768/* Can not be used to set time stamps yet (due to old DOS time format) */
5769/* Can be used to set attributes */
5770#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5771 handling it anyway and NT4 was what we thought it would be needed for
5772 Do not delete it until we prove whether needed for Win9x though */
5773int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005774CIFSSMBSetAttrLegacy(unsigned int xid, struct cifs_tcon *tcon, char *fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005775 __u16 dos_attrs, const struct nls_table *nls_codepage)
5776{
5777 SETATTR_REQ *pSMB = NULL;
5778 SETATTR_RSP *pSMBr = NULL;
5779 int rc = 0;
5780 int bytes_returned;
5781 int name_len;
5782
Joe Perchesb6b38f72010-04-21 03:50:45 +00005783 cFYI(1, "In SetAttrLegacy");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005784
5785SetAttrLgcyRetry:
5786 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5787 (void **) &pSMBr);
5788 if (rc)
5789 return rc;
5790
5791 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5792 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005793 ConvertToUTF16((__le16 *) pSMB->fileName, fileName,
5794 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005795 name_len++; /* trailing null */
5796 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005797 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005798 name_len = strnlen(fileName, PATH_MAX);
5799 name_len++; /* trailing null */
5800 strncpy(pSMB->fileName, fileName, name_len);
5801 }
5802 pSMB->attr = cpu_to_le16(dos_attrs);
5803 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005804 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005805 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5806 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5807 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005808 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005809 cFYI(1, "Error in LegacySetAttr = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005810
5811 cifs_buf_release(pSMB);
5812
5813 if (rc == -EAGAIN)
5814 goto SetAttrLgcyRetry;
5815
5816 return rc;
5817}
5818#endif /* temporarily unneeded SetAttr legacy function */
5819
Jeff Layton654cf142009-07-09 20:02:49 -04005820static void
5821cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5822 const struct cifs_unix_set_info_args *args)
5823{
Eric W. Biederman49418b22013-02-06 00:57:56 -08005824 u64 uid = NO_CHANGE_64, gid = NO_CHANGE_64;
Jeff Layton654cf142009-07-09 20:02:49 -04005825 u64 mode = args->mode;
5826
Eric W. Biederman49418b22013-02-06 00:57:56 -08005827 if (uid_valid(args->uid))
5828 uid = from_kuid(&init_user_ns, args->uid);
5829 if (gid_valid(args->gid))
5830 gid = from_kgid(&init_user_ns, args->gid);
5831
Jeff Layton654cf142009-07-09 20:02:49 -04005832 /*
5833 * Samba server ignores set of file size to zero due to bugs in some
5834 * older clients, but we should be precise - we use SetFileSize to
5835 * set file size and do not want to truncate file size to zero
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005836 * accidentally as happened on one Samba server beta by putting
Jeff Layton654cf142009-07-09 20:02:49 -04005837 * zero instead of -1 here
5838 */
5839 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5840 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5841 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5842 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5843 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
Eric W. Biederman49418b22013-02-06 00:57:56 -08005844 data_offset->Uid = cpu_to_le64(uid);
5845 data_offset->Gid = cpu_to_le64(gid);
Jeff Layton654cf142009-07-09 20:02:49 -04005846 /* better to leave device as zero when it is */
5847 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5848 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5849 data_offset->Permissions = cpu_to_le64(mode);
5850
5851 if (S_ISREG(mode))
5852 data_offset->Type = cpu_to_le32(UNIX_FILE);
5853 else if (S_ISDIR(mode))
5854 data_offset->Type = cpu_to_le32(UNIX_DIR);
5855 else if (S_ISLNK(mode))
5856 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5857 else if (S_ISCHR(mode))
5858 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5859 else if (S_ISBLK(mode))
5860 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5861 else if (S_ISFIFO(mode))
5862 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5863 else if (S_ISSOCK(mode))
5864 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5865}
5866
Linus Torvalds1da177e2005-04-16 15:20:36 -07005867int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005868CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005869 const struct cifs_unix_set_info_args *args,
5870 u16 fid, u32 pid_of_opener)
5871{
5872 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005873 char *data_offset;
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005874 int rc = 0;
5875 u16 params, param_offset, offset, byte_count, count;
5876
Joe Perchesb6b38f72010-04-21 03:50:45 +00005877 cFYI(1, "Set Unix Info (via SetFileInfo)");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005878 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5879
5880 if (rc)
5881 return rc;
5882
5883 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5884 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5885
5886 params = 6;
5887 pSMB->MaxSetupCount = 0;
5888 pSMB->Reserved = 0;
5889 pSMB->Flags = 0;
5890 pSMB->Timeout = 0;
5891 pSMB->Reserved2 = 0;
5892 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5893 offset = param_offset + params;
5894
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005895 data_offset = (char *)pSMB +
5896 offsetof(struct smb_hdr, Protocol) + offset;
5897
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005898 count = sizeof(FILE_UNIX_BASIC_INFO);
5899
5900 pSMB->MaxParameterCount = cpu_to_le16(2);
5901 /* BB find max SMB PDU from sess */
5902 pSMB->MaxDataCount = cpu_to_le16(1000);
5903 pSMB->SetupCount = 1;
5904 pSMB->Reserved3 = 0;
5905 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5906 byte_count = 3 /* pad */ + params + count;
5907 pSMB->DataCount = cpu_to_le16(count);
5908 pSMB->ParameterCount = cpu_to_le16(params);
5909 pSMB->TotalDataCount = pSMB->DataCount;
5910 pSMB->TotalParameterCount = pSMB->ParameterCount;
5911 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5912 pSMB->DataOffset = cpu_to_le16(offset);
5913 pSMB->Fid = fid;
5914 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5915 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005916 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005917 pSMB->ByteCount = cpu_to_le16(byte_count);
5918
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005919 cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005920
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005921 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005922 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005923 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005924
5925 /* Note: On -EAGAIN error only caller can retry on handle based calls
5926 since file handle passed in no longer valid */
5927
5928 return rc;
5929}
5930
5931int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005932CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005933 const char *file_name,
Jeff Layton01ea95e2009-07-09 20:02:49 -04005934 const struct cifs_unix_set_info_args *args,
5935 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005936{
5937 TRANSACTION2_SPI_REQ *pSMB = NULL;
5938 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5939 int name_len;
5940 int rc = 0;
5941 int bytes_returned = 0;
5942 FILE_UNIX_BASIC_INFO *data_offset;
5943 __u16 params, param_offset, offset, count, byte_count;
5944
Joe Perchesb6b38f72010-04-21 03:50:45 +00005945 cFYI(1, "In SetUID/GID/Mode");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005946setPermsRetry:
5947 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5948 (void **) &pSMBr);
5949 if (rc)
5950 return rc;
5951
5952 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5953 name_len =
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005954 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06005955 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005956 name_len++; /* trailing null */
5957 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005958 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005959 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005960 name_len++; /* trailing null */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005961 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005962 }
5963
5964 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005965 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005966 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005967 /* BB find max SMB PDU from sess structure BB */
5968 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005969 pSMB->MaxSetupCount = 0;
5970 pSMB->Reserved = 0;
5971 pSMB->Flags = 0;
5972 pSMB->Timeout = 0;
5973 pSMB->Reserved2 = 0;
5974 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005975 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005976 offset = param_offset + params;
5977 data_offset =
5978 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5979 offset);
5980 memset(data_offset, 0, count);
5981 pSMB->DataOffset = cpu_to_le16(offset);
5982 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5983 pSMB->SetupCount = 1;
5984 pSMB->Reserved3 = 0;
5985 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5986 byte_count = 3 /* pad */ + params + count;
5987 pSMB->ParameterCount = cpu_to_le16(params);
5988 pSMB->DataCount = cpu_to_le16(count);
5989 pSMB->TotalParameterCount = pSMB->ParameterCount;
5990 pSMB->TotalDataCount = pSMB->DataCount;
5991 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5992 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005993 inc_rfc1001_len(pSMB, byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005994
Jeff Layton654cf142009-07-09 20:02:49 -04005995 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005996
5997 pSMB->ByteCount = cpu_to_le16(byte_count);
5998 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5999 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006000 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00006001 cFYI(1, "SetPathInfo (perms) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006002
Steve French0d817bc2008-05-22 02:02:03 +00006003 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006004 if (rc == -EAGAIN)
6005 goto setPermsRetry;
6006 return rc;
6007}
6008
Linus Torvalds1da177e2005-04-16 15:20:36 -07006009#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05006010/*
6011 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
6012 * function used by listxattr and getxattr type calls. When ea_name is set,
6013 * it looks for that attribute name and stuffs that value into the EAData
6014 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
6015 * buffer. In both cases, the return value is either the length of the
6016 * resulting data or a negative error code. If EAData is a NULL pointer then
6017 * the data isn't copied to it, but the length is returned.
6018 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006019ssize_t
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006020CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05006021 const unsigned char *searchName, const unsigned char *ea_name,
6022 char *EAData, size_t buf_size,
6023 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006024{
6025 /* BB assumes one setup word */
6026 TRANSACTION2_QPI_REQ *pSMB = NULL;
6027 TRANSACTION2_QPI_RSP *pSMBr = NULL;
6028 int rc = 0;
6029 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05006030 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006031 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00006032 struct fea *temp_fea;
6033 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006034 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006035 __u16 params, byte_count, data_offset;
Jeff Layton5980fc92011-07-28 12:48:26 -04006036 unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006037
Joe Perchesb6b38f72010-04-21 03:50:45 +00006038 cFYI(1, "In Query All EAs path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006039QAllEAsRetry:
6040 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6041 (void **) &pSMBr);
6042 if (rc)
6043 return rc;
6044
6045 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05006046 list_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006047 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
6048 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05006049 list_len++; /* trailing null */
6050 list_len *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006051 } else { /* BB improve the check for buffer overruns BB */
Jeff Layton6e462b92010-02-10 16:18:26 -05006052 list_len = strnlen(searchName, PATH_MAX);
6053 list_len++; /* trailing null */
6054 strncpy(pSMB->FileName, searchName, list_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006055 }
6056
Jeff Layton6e462b92010-02-10 16:18:26 -05006057 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006058 pSMB->TotalDataCount = 0;
6059 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006060 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05006061 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006062 pSMB->MaxSetupCount = 0;
6063 pSMB->Reserved = 0;
6064 pSMB->Flags = 0;
6065 pSMB->Timeout = 0;
6066 pSMB->Reserved2 = 0;
6067 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00006068 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006069 pSMB->DataCount = 0;
6070 pSMB->DataOffset = 0;
6071 pSMB->SetupCount = 1;
6072 pSMB->Reserved3 = 0;
6073 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
6074 byte_count = params + 1 /* pad */ ;
6075 pSMB->TotalParameterCount = cpu_to_le16(params);
6076 pSMB->ParameterCount = pSMB->TotalParameterCount;
6077 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
6078 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006079 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006080 pSMB->ByteCount = cpu_to_le16(byte_count);
6081
6082 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6083 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6084 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006085 cFYI(1, "Send error in QueryAllEAs = %d", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05006086 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006087 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006088
6089
6090 /* BB also check enough total bytes returned */
6091 /* BB we need to improve the validity checking
6092 of these trans2 responses */
6093
6094 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Jeff Layton820a8032011-05-04 08:05:26 -04006095 if (rc || get_bcc(&pSMBr->hdr) < 4) {
Jeff Laytonf0d38682010-02-10 16:18:26 -05006096 rc = -EIO; /* bad smb */
6097 goto QAllEAsOut;
6098 }
6099
6100 /* check that length of list is not more than bcc */
6101 /* check that each entry does not go beyond length
6102 of list */
6103 /* check that each element of each entry does not
6104 go beyond end of list */
6105 /* validate_trans2_offsets() */
6106 /* BB check if start of smb + data_offset > &bcc+ bcc */
6107
6108 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
6109 ea_response_data = (struct fealist *)
6110 (((char *) &pSMBr->hdr.Protocol) + data_offset);
6111
Jeff Layton6e462b92010-02-10 16:18:26 -05006112 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesb6b38f72010-04-21 03:50:45 +00006113 cFYI(1, "ea length %d", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05006114 if (list_len <= 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006115 cFYI(1, "empty EA list returned from server");
Jeff Laytonf0d38682010-02-10 16:18:26 -05006116 goto QAllEAsOut;
6117 }
6118
Jeff Layton0cd126b2010-02-10 16:18:26 -05006119 /* make sure list_len doesn't go past end of SMB */
Jeff Layton690c5222011-01-20 13:36:51 -05006120 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
Jeff Layton0cd126b2010-02-10 16:18:26 -05006121 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006122 cFYI(1, "EA list appears to go beyond SMB");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006123 rc = -EIO;
6124 goto QAllEAsOut;
6125 }
6126
Jeff Laytonf0d38682010-02-10 16:18:26 -05006127 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05006128 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006129 temp_fea = ea_response_data->list;
6130 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05006131 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00006132 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006133 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006134
Jeff Layton6e462b92010-02-10 16:18:26 -05006135 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006136 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006137 /* make sure we can read name_len and value_len */
6138 if (list_len < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006139 cFYI(1, "EA entry goes beyond length of list");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006140 rc = -EIO;
6141 goto QAllEAsOut;
6142 }
6143
6144 name_len = temp_fea->name_len;
6145 value_len = le16_to_cpu(temp_fea->value_len);
6146 list_len -= name_len + 1 + value_len;
6147 if (list_len < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006148 cFYI(1, "EA entry goes beyond length of list");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006149 rc = -EIO;
6150 goto QAllEAsOut;
6151 }
6152
Jeff Layton31c05192010-02-10 16:18:26 -05006153 if (ea_name) {
Jeff Layton91d065c2011-07-26 18:23:47 -04006154 if (ea_name_len == name_len &&
Jeff Laytonac423442011-10-11 06:41:32 -04006155 memcmp(ea_name, temp_ptr, name_len) == 0) {
Jeff Layton31c05192010-02-10 16:18:26 -05006156 temp_ptr += name_len + 1;
6157 rc = value_len;
6158 if (buf_size == 0)
6159 goto QAllEAsOut;
6160 if ((size_t)value_len > buf_size) {
6161 rc = -ERANGE;
6162 goto QAllEAsOut;
6163 }
6164 memcpy(EAData, temp_ptr, value_len);
6165 goto QAllEAsOut;
6166 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006167 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05006168 /* account for prefix user. and trailing null */
6169 rc += (5 + 1 + name_len);
6170 if (rc < (int) buf_size) {
6171 memcpy(EAData, "user.", 5);
6172 EAData += 5;
6173 memcpy(EAData, temp_ptr, name_len);
6174 EAData += name_len;
6175 /* null terminate name */
6176 *EAData = 0;
6177 ++EAData;
6178 } else if (buf_size == 0) {
6179 /* skip copy - calc size only */
6180 } else {
6181 /* stop before overrun buffer */
6182 rc = -ERANGE;
6183 break;
6184 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006185 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05006186 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006187 temp_fea = (struct fea *)temp_ptr;
6188 }
6189
Jeff Layton31c05192010-02-10 16:18:26 -05006190 /* didn't find the named attribute */
6191 if (ea_name)
6192 rc = -ENODATA;
6193
Jeff Laytonf0d38682010-02-10 16:18:26 -05006194QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00006195 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006196 if (rc == -EAGAIN)
6197 goto QAllEAsRetry;
6198
6199 return (ssize_t)rc;
6200}
6201
Linus Torvalds1da177e2005-04-16 15:20:36 -07006202int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006203CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
6204 const char *fileName, const char *ea_name, const void *ea_value,
Steve French50c2f752007-07-13 00:33:32 +00006205 const __u16 ea_value_len, const struct nls_table *nls_codepage,
6206 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006207{
6208 struct smb_com_transaction2_spi_req *pSMB = NULL;
6209 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
6210 struct fealist *parm_data;
6211 int name_len;
6212 int rc = 0;
6213 int bytes_returned = 0;
6214 __u16 params, param_offset, byte_count, offset, count;
6215
Joe Perchesb6b38f72010-04-21 03:50:45 +00006216 cFYI(1, "In SetEA");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006217SetEARetry:
6218 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6219 (void **) &pSMBr);
6220 if (rc)
6221 return rc;
6222
6223 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6224 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006225 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
6226 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006227 name_len++; /* trailing null */
6228 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00006229 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006230 name_len = strnlen(fileName, PATH_MAX);
6231 name_len++; /* trailing null */
6232 strncpy(pSMB->FileName, fileName, name_len);
6233 }
6234
6235 params = 6 + name_len;
6236
6237 /* done calculating parms using name_len of file name,
6238 now use name_len to calculate length of ea name
6239 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00006240 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006241 name_len = 0;
6242 else
Steve French50c2f752007-07-13 00:33:32 +00006243 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006244
Steve Frenchdae5dbd2007-12-30 23:49:57 +00006245 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006246 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006247 /* BB find max SMB PDU from sess */
6248 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006249 pSMB->MaxSetupCount = 0;
6250 pSMB->Reserved = 0;
6251 pSMB->Flags = 0;
6252 pSMB->Timeout = 0;
6253 pSMB->Reserved2 = 0;
6254 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006255 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006256 offset = param_offset + params;
6257 pSMB->InformationLevel =
6258 cpu_to_le16(SMB_SET_FILE_EA);
6259
6260 parm_data =
6261 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
6262 offset);
6263 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6264 pSMB->DataOffset = cpu_to_le16(offset);
6265 pSMB->SetupCount = 1;
6266 pSMB->Reserved3 = 0;
6267 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6268 byte_count = 3 /* pad */ + params + count;
6269 pSMB->DataCount = cpu_to_le16(count);
6270 parm_data->list_len = cpu_to_le32(count);
6271 parm_data->list[0].EA_flags = 0;
6272 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08006273 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006274 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00006275 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00006276 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006277 parm_data->list[0].name[name_len] = 0;
6278 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
6279 /* caller ensures that ea_value_len is less than 64K but
6280 we need to ensure that it fits within the smb */
6281
Steve French50c2f752007-07-13 00:33:32 +00006282 /*BB add length check to see if it would fit in
6283 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00006284 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
6285 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00006286 memcpy(parm_data->list[0].name+name_len+1,
6287 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006288
6289 pSMB->TotalDataCount = pSMB->DataCount;
6290 pSMB->ParameterCount = cpu_to_le16(params);
6291 pSMB->TotalParameterCount = pSMB->ParameterCount;
6292 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006293 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006294 pSMB->ByteCount = cpu_to_le16(byte_count);
6295 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6296 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006297 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00006298 cFYI(1, "SetPathInfo (EA) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006299
6300 cifs_buf_release(pSMB);
6301
6302 if (rc == -EAGAIN)
6303 goto SetEARetry;
6304
6305 return rc;
6306}
Linus Torvalds1da177e2005-04-16 15:20:36 -07006307#endif
Steve French0eff0e22011-02-24 05:39:23 +00006308
6309#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */
6310/*
6311 * Years ago the kernel added a "dnotify" function for Samba server,
6312 * to allow network clients (such as Windows) to display updated
6313 * lists of files in directory listings automatically when
6314 * files are added by one user when another user has the
6315 * same directory open on their desktop. The Linux cifs kernel
6316 * client hooked into the kernel side of this interface for
6317 * the same reason, but ironically when the VFS moved from
6318 * "dnotify" to "inotify" it became harder to plug in Linux
6319 * network file system clients (the most obvious use case
6320 * for notify interfaces is when multiple users can update
6321 * the contents of the same directory - exactly what network
6322 * file systems can do) although the server (Samba) could
6323 * still use it. For the short term we leave the worker
6324 * function ifdeffed out (below) until inotify is fixed
6325 * in the VFS to make it easier to plug in network file
6326 * system clients. If inotify turns out to be permanently
6327 * incompatible for network fs clients, we could instead simply
6328 * expose this config flag by adding a future cifs (and smb2) notify ioctl.
6329 */
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006330int CIFSSMBNotify(const unsigned int xid, struct cifs_tcon *tcon,
Steve French0eff0e22011-02-24 05:39:23 +00006331 const int notify_subdirs, const __u16 netfid,
6332 __u32 filter, struct file *pfile, int multishot,
6333 const struct nls_table *nls_codepage)
6334{
6335 int rc = 0;
6336 struct smb_com_transaction_change_notify_req *pSMB = NULL;
6337 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
6338 struct dir_notify_req *dnotify_req;
6339 int bytes_returned;
6340
6341 cFYI(1, "In CIFSSMBNotify for file handle %d", (int)netfid);
6342 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
6343 (void **) &pSMBr);
6344 if (rc)
6345 return rc;
6346
6347 pSMB->TotalParameterCount = 0 ;
6348 pSMB->TotalDataCount = 0;
6349 pSMB->MaxParameterCount = cpu_to_le32(2);
Jeff Laytonc974bef2011-10-11 06:41:32 -04006350 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Steve French0eff0e22011-02-24 05:39:23 +00006351 pSMB->MaxSetupCount = 4;
6352 pSMB->Reserved = 0;
6353 pSMB->ParameterOffset = 0;
6354 pSMB->DataCount = 0;
6355 pSMB->DataOffset = 0;
6356 pSMB->SetupCount = 4; /* single byte does not need le conversion */
6357 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
6358 pSMB->ParameterCount = pSMB->TotalParameterCount;
6359 if (notify_subdirs)
6360 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
6361 pSMB->Reserved2 = 0;
6362 pSMB->CompletionFilter = cpu_to_le32(filter);
6363 pSMB->Fid = netfid; /* file handle always le */
6364 pSMB->ByteCount = 0;
6365
6366 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6367 (struct smb_hdr *)pSMBr, &bytes_returned,
6368 CIFS_ASYNC_OP);
6369 if (rc) {
6370 cFYI(1, "Error in Notify = %d", rc);
6371 } else {
6372 /* Add file to outstanding requests */
6373 /* BB change to kmem cache alloc */
6374 dnotify_req = kmalloc(
6375 sizeof(struct dir_notify_req),
6376 GFP_KERNEL);
6377 if (dnotify_req) {
6378 dnotify_req->Pid = pSMB->hdr.Pid;
6379 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
6380 dnotify_req->Mid = pSMB->hdr.Mid;
6381 dnotify_req->Tid = pSMB->hdr.Tid;
6382 dnotify_req->Uid = pSMB->hdr.Uid;
6383 dnotify_req->netfid = netfid;
6384 dnotify_req->pfile = pfile;
6385 dnotify_req->filter = filter;
6386 dnotify_req->multishot = multishot;
6387 spin_lock(&GlobalMid_Lock);
6388 list_add_tail(&dnotify_req->lhead,
6389 &GlobalDnotifyReqList);
6390 spin_unlock(&GlobalMid_Lock);
6391 } else
6392 rc = -ENOMEM;
6393 }
6394 cifs_buf_release(pSMB);
6395 return rc;
6396}
6397#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */