blob: b8cd335d6f11121a6e44a38e4c815b995e63b4c4 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/cifssmb.c
3 *
Steve Frenchf19159d2010-04-21 04:12:10 +00004 * Copyright (C) International Business Machines Corp., 2002,2010
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * Author(s): Steve French (sfrench@us.ibm.com)
6 *
7 * Contains the routines for constructing the SMB PDUs themselves
8 *
9 * This library is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as published
11 * by the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
17 * the GNU Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24 /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c */
25 /* These are mostly routines that operate on a pathname, or on a tree id */
26 /* (mounted volume), but there are eight handle based routines which must be */
Steve French2dd29d32007-04-23 22:07:35 +000027 /* treated slightly differently for reconnection purposes since we never */
28 /* want to reuse a stale file handle and only the caller knows the file info */
Linus Torvalds1da177e2005-04-16 15:20:36 -070029
30#include <linux/fs.h>
31#include <linux/kernel.h>
32#include <linux/vfs.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090033#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include <linux/posix_acl_xattr.h>
Jeff Laytonc28c89f2011-05-19 16:22:56 -040035#include <linux/pagemap.h>
Jeff Laytone28bc5b2011-10-19 15:30:07 -040036#include <linux/swap.h>
37#include <linux/task_io_accounting_ops.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070038#include <asm/uaccess.h>
39#include "cifspdu.h"
40#include "cifsglob.h"
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +000041#include "cifsacl.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070042#include "cifsproto.h"
43#include "cifs_unicode.h"
44#include "cifs_debug.h"
Jeff Laytone28bc5b2011-10-19 15:30:07 -040045#include "fscache.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070046
47#ifdef CONFIG_CIFS_POSIX
48static struct {
49 int index;
50 char *name;
51} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000052#ifdef CONFIG_CIFS_WEAK_PW_HASH
53 {LANMAN_PROT, "\2LM1.2X002"},
Steve French9ac00b72006-09-30 04:13:17 +000054 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000055#endif /* weak password hashing for legacy clients */
Steve French50c2f752007-07-13 00:33:32 +000056 {CIFS_PROT, "\2NT LM 0.12"},
Steve French39798772006-05-31 22:40:51 +000057 {POSIX_PROT, "\2POSIX 2"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070058 {BAD_PROT, "\2"}
59};
60#else
61static struct {
62 int index;
63 char *name;
64} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000065#ifdef CONFIG_CIFS_WEAK_PW_HASH
66 {LANMAN_PROT, "\2LM1.2X002"},
Steve French18f75ca2006-10-01 03:13:01 +000067 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000068#endif /* weak password hashing for legacy clients */
Steve French790fe572007-07-07 19:25:05 +000069 {CIFS_PROT, "\2NT LM 0.12"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070070 {BAD_PROT, "\2"}
71};
72#endif
73
Steve French39798772006-05-31 22:40:51 +000074/* define the number of elements in the cifs dialect array */
75#ifdef CONFIG_CIFS_POSIX
76#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000077#define CIFS_NUM_PROT 4
Steve French39798772006-05-31 22:40:51 +000078#else
79#define CIFS_NUM_PROT 2
80#endif /* CIFS_WEAK_PW_HASH */
81#else /* not posix */
82#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000083#define CIFS_NUM_PROT 3
Steve French39798772006-05-31 22:40:51 +000084#else
85#define CIFS_NUM_PROT 1
86#endif /* CONFIG_CIFS_WEAK_PW_HASH */
87#endif /* CIFS_POSIX */
88
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +040089/*
90 * Mark as invalid, all open files on tree connections since they
91 * were closed when session to server was lost.
92 */
93void
94cifs_mark_open_files_invalid(struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -070095{
96 struct cifsFileInfo *open_file = NULL;
Steve French790fe572007-07-07 19:25:05 +000097 struct list_head *tmp;
98 struct list_head *tmp1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070099
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400100 /* list all files open on tree connection and mark them invalid */
Jeff Layton44772882010-10-15 15:34:03 -0400101 spin_lock(&cifs_file_list_lock);
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400102 list_for_each_safe(tmp, tmp1, &tcon->openFileList) {
Steve French790fe572007-07-07 19:25:05 +0000103 open_file = list_entry(tmp, struct cifsFileInfo, tlist);
Steve Frenchad8b15f2008-08-08 21:10:16 +0000104 open_file->invalidHandle = true;
Jeff Layton3bc303c2009-09-21 06:47:50 -0400105 open_file->oplock_break_cancelled = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106 }
Jeff Layton44772882010-10-15 15:34:03 -0400107 spin_unlock(&cifs_file_list_lock);
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400108 /*
109 * BB Add call to invalidate_inodes(sb) for all superblocks mounted
110 * to this tcon.
111 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112}
113
Jeff Layton9162ab22009-09-03 12:07:17 -0400114/* reconnect the socket, tcon, and smb session if needed */
115static int
Steve French96daf2b2011-05-27 04:34:02 +0000116cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
Jeff Layton9162ab22009-09-03 12:07:17 -0400117{
Jeff Laytonc4a55342011-07-28 12:40:36 -0400118 int rc;
Steve French96daf2b2011-05-27 04:34:02 +0000119 struct cifs_ses *ses;
Jeff Layton9162ab22009-09-03 12:07:17 -0400120 struct TCP_Server_Info *server;
121 struct nls_table *nls_codepage;
122
123 /*
124 * SMBs NegProt, SessSetup, uLogoff do not have tcon yet so check for
125 * tcp and smb session status done differently for those three - in the
126 * calling routine
127 */
128 if (!tcon)
129 return 0;
130
131 ses = tcon->ses;
132 server = ses->server;
133
134 /*
135 * only tree disconnect, open, and write, (and ulogoff which does not
136 * have tcon) are allowed as we start force umount
137 */
138 if (tcon->tidStatus == CifsExiting) {
139 if (smb_command != SMB_COM_WRITE_ANDX &&
140 smb_command != SMB_COM_OPEN_ANDX &&
141 smb_command != SMB_COM_TREE_DISCONNECT) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000142 cFYI(1, "can not send cmd %d while umounting",
143 smb_command);
Jeff Layton9162ab22009-09-03 12:07:17 -0400144 return -ENODEV;
145 }
146 }
147
Jeff Layton9162ab22009-09-03 12:07:17 -0400148 /*
149 * Give demultiplex thread up to 10 seconds to reconnect, should be
150 * greater than cifs socket timeout which is 7 seconds
151 */
152 while (server->tcpStatus == CifsNeedReconnect) {
153 wait_event_interruptible_timeout(server->response_q,
Steve Frenchfd88ce92011-04-12 01:01:14 +0000154 (server->tcpStatus != CifsNeedReconnect), 10 * HZ);
Jeff Layton9162ab22009-09-03 12:07:17 -0400155
Steve Frenchfd88ce92011-04-12 01:01:14 +0000156 /* are we still trying to reconnect? */
Jeff Layton9162ab22009-09-03 12:07:17 -0400157 if (server->tcpStatus != CifsNeedReconnect)
158 break;
159
160 /*
161 * on "soft" mounts we wait once. Hard mounts keep
162 * retrying until process is killed or server comes
163 * back on-line
164 */
Jeff Laytond4025392011-02-07 08:54:35 -0500165 if (!tcon->retry) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000166 cFYI(1, "gave up waiting on reconnect in smb_init");
Jeff Layton9162ab22009-09-03 12:07:17 -0400167 return -EHOSTDOWN;
168 }
169 }
170
171 if (!ses->need_reconnect && !tcon->need_reconnect)
172 return 0;
173
174 nls_codepage = load_nls_default();
175
176 /*
177 * need to prevent multiple threads trying to simultaneously
178 * reconnect the same SMB session
179 */
Steve Frenchd7b619c2010-02-25 05:36:46 +0000180 mutex_lock(&ses->session_mutex);
Jeff Layton198b5682010-04-24 07:57:48 -0400181 rc = cifs_negotiate_protocol(0, ses);
182 if (rc == 0 && ses->need_reconnect)
Jeff Layton9162ab22009-09-03 12:07:17 -0400183 rc = cifs_setup_session(0, ses, nls_codepage);
184
185 /* do we need to reconnect tcon? */
186 if (rc || !tcon->need_reconnect) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000187 mutex_unlock(&ses->session_mutex);
Jeff Layton9162ab22009-09-03 12:07:17 -0400188 goto out;
189 }
190
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400191 cifs_mark_open_files_invalid(tcon);
Jeff Layton9162ab22009-09-03 12:07:17 -0400192 rc = CIFSTCon(0, ses, tcon->treeName, tcon, nls_codepage);
Steve Frenchd7b619c2010-02-25 05:36:46 +0000193 mutex_unlock(&ses->session_mutex);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000194 cFYI(1, "reconnect tcon rc = %d", rc);
Jeff Layton9162ab22009-09-03 12:07:17 -0400195
196 if (rc)
197 goto out;
198
199 /*
200 * FIXME: check if wsize needs updated due to negotiated smb buffer
201 * size shrinking
202 */
203 atomic_inc(&tconInfoReconnectCount);
204
205 /* tell server Unix caps we support */
206 if (ses->capabilities & CAP_UNIX)
207 reset_cifs_unix_caps(0, tcon, NULL, NULL);
208
209 /*
210 * Removed call to reopen open files here. It is safer (and faster) to
211 * reopen files one at a time as needed in read and write.
212 *
213 * FIXME: what about file locks? don't we need to reclaim them ASAP?
214 */
215
216out:
217 /*
218 * Check if handle based operation so we know whether we can continue
219 * or not without returning to caller to reset file handle
220 */
221 switch (smb_command) {
222 case SMB_COM_READ_ANDX:
223 case SMB_COM_WRITE_ANDX:
224 case SMB_COM_CLOSE:
225 case SMB_COM_FIND_CLOSE2:
226 case SMB_COM_LOCKING_ANDX:
227 rc = -EAGAIN;
228 }
229
230 unload_nls(nls_codepage);
231 return rc;
232}
233
Steve Frenchad7a2922008-02-07 23:25:02 +0000234/* Allocate and return pointer to an SMB request buffer, and set basic
235 SMB information in the SMB header. If the return code is zero, this
236 function must have filled in request_buf pointer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237static int
Steve French96daf2b2011-05-27 04:34:02 +0000238small_smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000239 void **request_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240{
Jeff Laytonf5695992010-09-29 15:27:08 -0400241 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242
Jeff Layton9162ab22009-09-03 12:07:17 -0400243 rc = cifs_reconnect_tcon(tcon, smb_command);
Steve French790fe572007-07-07 19:25:05 +0000244 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245 return rc;
246
247 *request_buf = cifs_small_buf_get();
248 if (*request_buf == NULL) {
249 /* BB should we add a retry in here if not a writepage? */
250 return -ENOMEM;
251 }
252
Steve French63135e02007-07-17 17:34:02 +0000253 header_assemble((struct smb_hdr *) *request_buf, smb_command,
Steve Frenchc18c8422007-07-18 23:21:09 +0000254 tcon, wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255
Steve French790fe572007-07-07 19:25:05 +0000256 if (tcon != NULL)
257 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700258
Jeff Laytonf5695992010-09-29 15:27:08 -0400259 return 0;
Steve French5815449d2006-02-14 01:36:20 +0000260}
261
Steve French12b3b8f2006-02-09 21:12:47 +0000262int
Steve French50c2f752007-07-13 00:33:32 +0000263small_smb_init_no_tc(const int smb_command, const int wct,
Steve French96daf2b2011-05-27 04:34:02 +0000264 struct cifs_ses *ses, void **request_buf)
Steve French12b3b8f2006-02-09 21:12:47 +0000265{
266 int rc;
Steve French50c2f752007-07-13 00:33:32 +0000267 struct smb_hdr *buffer;
Steve French12b3b8f2006-02-09 21:12:47 +0000268
Steve French5815449d2006-02-14 01:36:20 +0000269 rc = small_smb_init(smb_command, wct, NULL, request_buf);
Steve French790fe572007-07-07 19:25:05 +0000270 if (rc)
Steve French12b3b8f2006-02-09 21:12:47 +0000271 return rc;
272
Steve French04fdabe2006-02-10 05:52:50 +0000273 buffer = (struct smb_hdr *)*request_buf;
Pavel Shilovsky88257362012-05-23 14:01:59 +0400274 buffer->Mid = get_next_mid(ses->server);
Steve French12b3b8f2006-02-09 21:12:47 +0000275 if (ses->capabilities & CAP_UNICODE)
276 buffer->Flags2 |= SMBFLG2_UNICODE;
Steve French04fdabe2006-02-10 05:52:50 +0000277 if (ses->capabilities & CAP_STATUS32)
Steve French12b3b8f2006-02-09 21:12:47 +0000278 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
279
280 /* uid, tid can stay at zero as set in header assemble */
281
Steve French50c2f752007-07-13 00:33:32 +0000282 /* BB add support for turning on the signing when
Steve French12b3b8f2006-02-09 21:12:47 +0000283 this function is used after 1st of session setup requests */
284
285 return rc;
286}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287
288/* If the return code is zero, this function must fill in request_buf pointer */
289static int
Steve French96daf2b2011-05-27 04:34:02 +0000290__smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400291 void **request_buf, void **response_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293 *request_buf = cifs_buf_get();
294 if (*request_buf == NULL) {
295 /* BB should we add a retry in here if not a writepage? */
296 return -ENOMEM;
297 }
298 /* Although the original thought was we needed the response buf for */
299 /* potential retries of smb operations it turns out we can determine */
300 /* from the mid flags when the request buffer can be resent without */
301 /* having to use a second distinct buffer for the response */
Steve French790fe572007-07-07 19:25:05 +0000302 if (response_buf)
Steve French50c2f752007-07-13 00:33:32 +0000303 *response_buf = *request_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304
305 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000306 wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307
Steve French790fe572007-07-07 19:25:05 +0000308 if (tcon != NULL)
309 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700310
Jeff Laytonf5695992010-09-29 15:27:08 -0400311 return 0;
312}
313
314/* If the return code is zero, this function must fill in request_buf pointer */
315static int
Steve French96daf2b2011-05-27 04:34:02 +0000316smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400317 void **request_buf, void **response_buf)
318{
319 int rc;
320
321 rc = cifs_reconnect_tcon(tcon, smb_command);
322 if (rc)
323 return rc;
324
325 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
326}
327
328static int
Steve French96daf2b2011-05-27 04:34:02 +0000329smb_init_no_reconnect(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400330 void **request_buf, void **response_buf)
331{
332 if (tcon->ses->need_reconnect || tcon->need_reconnect)
333 return -EHOSTDOWN;
334
335 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336}
337
Steve French50c2f752007-07-13 00:33:32 +0000338static int validate_t2(struct smb_t2_rsp *pSMB)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339{
Jeff Layton12df83c2011-01-20 13:36:51 -0500340 unsigned int total_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341
Jeff Layton12df83c2011-01-20 13:36:51 -0500342 /* check for plausible wct */
343 if (pSMB->hdr.WordCount < 10)
344 goto vt2_err;
345
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346 /* check for parm and data offset going beyond end of smb */
Jeff Layton12df83c2011-01-20 13:36:51 -0500347 if (get_unaligned_le16(&pSMB->t2_rsp.ParameterOffset) > 1024 ||
348 get_unaligned_le16(&pSMB->t2_rsp.DataOffset) > 1024)
349 goto vt2_err;
350
Jeff Layton12df83c2011-01-20 13:36:51 -0500351 total_size = get_unaligned_le16(&pSMB->t2_rsp.ParameterCount);
352 if (total_size >= 512)
353 goto vt2_err;
354
Jeff Laytonfd5707e2011-03-31 17:22:07 -0400355 /* check that bcc is at least as big as parms + data, and that it is
356 * less than negotiated smb buffer
357 */
Jeff Layton12df83c2011-01-20 13:36:51 -0500358 total_size += get_unaligned_le16(&pSMB->t2_rsp.DataCount);
359 if (total_size > get_bcc(&pSMB->hdr) ||
360 total_size >= CIFSMaxBufSize + MAX_CIFS_HDR_SIZE)
361 goto vt2_err;
362
363 return 0;
364vt2_err:
Steve French50c2f752007-07-13 00:33:32 +0000365 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 sizeof(struct smb_t2_rsp) + 16);
Jeff Layton12df83c2011-01-20 13:36:51 -0500367 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368}
Jeff Layton690c5222011-01-20 13:36:51 -0500369
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370int
Pavel Shilovsky286170a2012-05-25 10:43:58 +0400371CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372{
373 NEGOTIATE_REQ *pSMB;
374 NEGOTIATE_RSP *pSMBr;
375 int rc = 0;
376 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000377 int i;
Steve French50c2f752007-07-13 00:33:32 +0000378 struct TCP_Server_Info *server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 u16 count;
Steve French750d1152006-06-27 06:28:30 +0000380 unsigned int secFlags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381
Steve French790fe572007-07-07 19:25:05 +0000382 if (ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 server = ses->server;
384 else {
385 rc = -EIO;
386 return rc;
387 }
388 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
389 (void **) &pSMB, (void **) &pSMBr);
390 if (rc)
391 return rc;
Steve French750d1152006-06-27 06:28:30 +0000392
393 /* if any of auth flags (ie not sign or seal) are overriden use them */
Steve French790fe572007-07-07 19:25:05 +0000394 if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
Steve French762e5ab2007-06-28 18:41:42 +0000395 secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
Steve French750d1152006-06-27 06:28:30 +0000396 else /* if override flags set only sign/seal OR them with global auth */
Jeff Layton04912d62010-04-24 07:57:45 -0400397 secFlags = global_secflags | ses->overrideSecFlg;
Steve French750d1152006-06-27 06:28:30 +0000398
Joe Perchesb6b38f72010-04-21 03:50:45 +0000399 cFYI(1, "secFlags 0x%x", secFlags);
Steve Frenchf40c5622006-06-28 00:13:38 +0000400
Pavel Shilovsky88257362012-05-23 14:01:59 +0400401 pSMB->hdr.Mid = get_next_mid(server);
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000402 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
Steve Frencha0136892007-10-04 20:05:09 +0000403
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000404 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
Steve French254e55e2006-06-04 05:53:15 +0000405 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Steve Frencha0136892007-10-04 20:05:09 +0000406 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000407 cFYI(1, "Kerberos only mechanism, enable extended security");
Steve Frencha0136892007-10-04 20:05:09 +0000408 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Jeff Laytonb4d6fcf2011-01-07 11:30:28 -0500409 } else if ((secFlags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP)
Steve Frenchac683922009-05-06 04:16:04 +0000410 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
411 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_NTLMSSP) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000412 cFYI(1, "NTLMSSP only mechanism, enable extended security");
Steve Frenchac683922009-05-06 04:16:04 +0000413 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
414 }
Steve French50c2f752007-07-13 00:33:32 +0000415
Steve French39798772006-05-31 22:40:51 +0000416 count = 0;
Steve French50c2f752007-07-13 00:33:32 +0000417 for (i = 0; i < CIFS_NUM_PROT; i++) {
Steve French39798772006-05-31 22:40:51 +0000418 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
419 count += strlen(protocols[i].name) + 1;
420 /* null at end of source and target buffers anyway */
421 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000422 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 pSMB->ByteCount = cpu_to_le16(count);
424
425 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
426 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French50c2f752007-07-13 00:33:32 +0000427 if (rc != 0)
Steve French254e55e2006-06-04 05:53:15 +0000428 goto neg_err_exit;
429
Jeff Layton9bf67e52010-04-24 07:57:46 -0400430 server->dialect = le16_to_cpu(pSMBr->DialectIndex);
431 cFYI(1, "Dialect: %d", server->dialect);
Steve French254e55e2006-06-04 05:53:15 +0000432 /* Check wct = 1 error case */
Jeff Layton9bf67e52010-04-24 07:57:46 -0400433 if ((pSMBr->hdr.WordCount < 13) || (server->dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000434 /* core returns wct = 1, but we do not ask for core - otherwise
Steve French50c2f752007-07-13 00:33:32 +0000435 small wct just comes when dialect index is -1 indicating we
Steve French254e55e2006-06-04 05:53:15 +0000436 could not negotiate a common dialect */
437 rc = -EOPNOTSUPP;
438 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000439#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French790fe572007-07-07 19:25:05 +0000440 } else if ((pSMBr->hdr.WordCount == 13)
Jeff Layton9bf67e52010-04-24 07:57:46 -0400441 && ((server->dialect == LANMAN_PROT)
442 || (server->dialect == LANMAN2_PROT))) {
Steve Frenchb815f1e52006-10-02 05:53:29 +0000443 __s16 tmp;
Steve French50c2f752007-07-13 00:33:32 +0000444 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
Steve French254e55e2006-06-04 05:53:15 +0000445
Steve French790fe572007-07-07 19:25:05 +0000446 if ((secFlags & CIFSSEC_MAY_LANMAN) ||
Steve French750d1152006-06-27 06:28:30 +0000447 (secFlags & CIFSSEC_MAY_PLNTXT))
Steve French254e55e2006-06-04 05:53:15 +0000448 server->secType = LANMAN;
449 else {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000450 cERROR(1, "mount failed weak security disabled"
451 " in /proc/fs/cifs/SecurityFlags");
Steve French39798772006-05-31 22:40:51 +0000452 rc = -EOPNOTSUPP;
453 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000454 }
Pavel Shilovsky286170a2012-05-25 10:43:58 +0400455 server->sec_mode = le16_to_cpu(rsp->SecurityMode);
Pavel Shilovsky10b9b982012-03-20 12:55:09 +0300456 server->maxReq = min_t(unsigned int,
457 le16_to_cpu(rsp->MaxMpxCount),
458 cifs_max_pending);
Pavel Shilovsky45275782012-05-17 17:53:29 +0400459 set_credits(server, server->maxReq);
Jeff Laytonc974bef2011-10-11 06:41:32 -0400460 server->maxBuf = le16_to_cpu(rsp->MaxBufSize);
Steve Frencheca6acf2009-02-20 05:43:09 +0000461 server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
Steve French254e55e2006-06-04 05:53:15 +0000462 /* even though we do not use raw we might as well set this
463 accurately, in case we ever find a need for it */
Steve French790fe572007-07-07 19:25:05 +0000464 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
Steve Frencheca6acf2009-02-20 05:43:09 +0000465 server->max_rw = 0xFF00;
Steve French254e55e2006-06-04 05:53:15 +0000466 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
467 } else {
Steve Frencheca6acf2009-02-20 05:43:09 +0000468 server->max_rw = 0;/* do not need to use raw anyway */
Steve French254e55e2006-06-04 05:53:15 +0000469 server->capabilities = CAP_MPX_MODE;
470 }
Steve Frenchb815f1e52006-10-02 05:53:29 +0000471 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
Steve French1a70d652006-10-02 05:59:18 +0000472 if (tmp == -1) {
Steve French25ee4a92006-09-30 00:54:23 +0000473 /* OS/2 often does not set timezone therefore
474 * we must use server time to calc time zone.
Steve Frenchb815f1e52006-10-02 05:53:29 +0000475 * Could deviate slightly from the right zone.
476 * Smallest defined timezone difference is 15 minutes
477 * (i.e. Nepal). Rounding up/down is done to match
478 * this requirement.
Steve French25ee4a92006-09-30 00:54:23 +0000479 */
Steve Frenchb815f1e52006-10-02 05:53:29 +0000480 int val, seconds, remain, result;
Steve French25ee4a92006-09-30 00:54:23 +0000481 struct timespec ts, utc;
482 utc = CURRENT_TIME;
Jeff Laytonc4a2c082009-05-27 09:37:33 -0400483 ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
484 rsp->SrvTime.Time, 0);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000485 cFYI(1, "SrvTime %d sec since 1970 (utc: %d) diff: %d",
Steve French50c2f752007-07-13 00:33:32 +0000486 (int)ts.tv_sec, (int)utc.tv_sec,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000487 (int)(utc.tv_sec - ts.tv_sec));
Steve Frenchb815f1e52006-10-02 05:53:29 +0000488 val = (int)(utc.tv_sec - ts.tv_sec);
Andre Haupt8594c152007-08-30 20:18:41 +0000489 seconds = abs(val);
Steve French947a5062006-10-02 05:55:25 +0000490 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
Steve Frenchb815f1e52006-10-02 05:53:29 +0000491 remain = seconds % MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000492 if (remain >= (MIN_TZ_ADJ / 2))
Steve Frenchb815f1e52006-10-02 05:53:29 +0000493 result += MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000494 if (val < 0)
Steve Frenchad7a2922008-02-07 23:25:02 +0000495 result = -result;
Steve Frenchb815f1e52006-10-02 05:53:29 +0000496 server->timeAdj = result;
Steve French25ee4a92006-09-30 00:54:23 +0000497 } else {
Steve Frenchb815f1e52006-10-02 05:53:29 +0000498 server->timeAdj = (int)tmp;
499 server->timeAdj *= 60; /* also in seconds */
Steve French25ee4a92006-09-30 00:54:23 +0000500 }
Joe Perchesb6b38f72010-04-21 03:50:45 +0000501 cFYI(1, "server->timeAdj: %d seconds", server->timeAdj);
Steve French25ee4a92006-09-30 00:54:23 +0000502
Steve French39798772006-05-31 22:40:51 +0000503
Steve French254e55e2006-06-04 05:53:15 +0000504 /* BB get server time for time conversions and add
Steve French50c2f752007-07-13 00:33:32 +0000505 code to use it and timezone since this is not UTC */
Steve French39798772006-05-31 22:40:51 +0000506
Steve French50c2f752007-07-13 00:33:32 +0000507 if (rsp->EncryptionKeyLength ==
Steve French25ee4a92006-09-30 00:54:23 +0000508 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500509 memcpy(ses->server->cryptkey, rsp->EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000510 CIFS_CRYPTO_KEY_SIZE);
Steve French96daf2b2011-05-27 04:34:02 +0000511 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
Steve French254e55e2006-06-04 05:53:15 +0000512 rc = -EIO; /* need cryptkey unless plain text */
513 goto neg_err_exit;
514 }
Steve French39798772006-05-31 22:40:51 +0000515
Steve Frenchf19159d2010-04-21 04:12:10 +0000516 cFYI(1, "LANMAN negotiated");
Steve French254e55e2006-06-04 05:53:15 +0000517 /* we will not end up setting signing flags - as no signing
518 was in LANMAN and server did not return the flags on */
519 goto signing_check;
Steve French7c7b25b2006-06-01 19:20:10 +0000520#else /* weak security disabled */
Steve French790fe572007-07-07 19:25:05 +0000521 } else if (pSMBr->hdr.WordCount == 13) {
Steve Frenchf19159d2010-04-21 04:12:10 +0000522 cERROR(1, "mount failed, cifs module not built "
523 "with CIFS_WEAK_PW_HASH support");
Dan Carpenter8212cf72010-03-15 11:22:26 +0300524 rc = -EOPNOTSUPP;
Steve French7c7b25b2006-06-01 19:20:10 +0000525#endif /* WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000526 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000527 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000528 /* unknown wct */
529 rc = -EOPNOTSUPP;
530 goto neg_err_exit;
531 }
532 /* else wct == 17 NTLM */
Steve French96daf2b2011-05-27 04:34:02 +0000533 server->sec_mode = pSMBr->SecurityMode;
534 if ((server->sec_mode & SECMODE_USER) == 0)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000535 cFYI(1, "share mode security");
Steve French39798772006-05-31 22:40:51 +0000536
Steve French96daf2b2011-05-27 04:34:02 +0000537 if ((server->sec_mode & SECMODE_PW_ENCRYPT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000538#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French750d1152006-06-27 06:28:30 +0000539 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000540#endif /* CIFS_WEAK_PW_HASH */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000541 cERROR(1, "Server requests plain text password"
542 " but client support disabled");
Steve French9312f672006-06-04 22:21:07 +0000543
Steve French790fe572007-07-07 19:25:05 +0000544 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
Steve French254e55e2006-06-04 05:53:15 +0000545 server->secType = NTLMv2;
Steve French790fe572007-07-07 19:25:05 +0000546 else if (secFlags & CIFSSEC_MAY_NTLM)
Steve French254e55e2006-06-04 05:53:15 +0000547 server->secType = NTLM;
Steve French790fe572007-07-07 19:25:05 +0000548 else if (secFlags & CIFSSEC_MAY_NTLMV2)
Steve Frenchf40c5622006-06-28 00:13:38 +0000549 server->secType = NTLMv2;
Steve Frencha0136892007-10-04 20:05:09 +0000550 else if (secFlags & CIFSSEC_MAY_KRB5)
551 server->secType = Kerberos;
Steve Frenchac683922009-05-06 04:16:04 +0000552 else if (secFlags & CIFSSEC_MAY_NTLMSSP)
Steve Frenchf46c7232009-06-25 03:04:20 +0000553 server->secType = RawNTLMSSP;
Steve Frencha0136892007-10-04 20:05:09 +0000554 else if (secFlags & CIFSSEC_MAY_LANMAN)
555 server->secType = LANMAN;
Steve Frencha0136892007-10-04 20:05:09 +0000556 else {
557 rc = -EOPNOTSUPP;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000558 cERROR(1, "Invalid security type");
Steve Frencha0136892007-10-04 20:05:09 +0000559 goto neg_err_exit;
560 }
561 /* else ... any others ...? */
Steve French7c7b25b2006-06-01 19:20:10 +0000562
Steve French254e55e2006-06-04 05:53:15 +0000563 /* one byte, so no need to convert this or EncryptionKeyLen from
564 little endian */
Pavel Shilovsky10b9b982012-03-20 12:55:09 +0300565 server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount),
566 cifs_max_pending);
Pavel Shilovsky45275782012-05-17 17:53:29 +0400567 set_credits(server, server->maxReq);
Steve French254e55e2006-06-04 05:53:15 +0000568 /* probably no need to store and check maxvcs */
Jeff Laytonc974bef2011-10-11 06:41:32 -0400569 server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize);
Steve Frencheca6acf2009-02-20 05:43:09 +0000570 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000571 cFYI(DBG2, "Max buf = %d", ses->server->maxBuf);
Steve French254e55e2006-06-04 05:53:15 +0000572 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e52006-10-02 05:53:29 +0000573 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
574 server->timeAdj *= 60;
Steve French254e55e2006-06-04 05:53:15 +0000575 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500576 memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000577 CIFS_CRYPTO_KEY_SIZE);
Steve French07cc6cf2011-05-27 04:12:29 +0000578 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC ||
579 server->capabilities & CAP_EXTENDED_SECURITY) &&
580 (pSMBr->EncryptionKeyLength == 0)) {
Steve French254e55e2006-06-04 05:53:15 +0000581 /* decode security blob */
Jeff Layton820a8032011-05-04 08:05:26 -0400582 count = get_bcc(&pSMBr->hdr);
Jeff Laytone187e442007-10-16 17:10:44 +0000583 if (count < 16) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 rc = -EIO;
Jeff Laytone187e442007-10-16 17:10:44 +0000585 goto neg_err_exit;
586 }
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530587 spin_lock(&cifs_tcp_ses_lock);
Jeff Laytone7ddee92008-11-14 13:44:38 -0500588 if (server->srv_count > 1) {
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530589 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000590 if (memcmp(server->server_GUID,
591 pSMBr->u.extended_response.
592 GUID, 16) != 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000593 cFYI(1, "server UID changed");
Steve French254e55e2006-06-04 05:53:15 +0000594 memcpy(server->server_GUID,
Jeff Laytone187e442007-10-16 17:10:44 +0000595 pSMBr->u.extended_response.GUID,
596 16);
597 }
Jeff Laytone7ddee92008-11-14 13:44:38 -0500598 } else {
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530599 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000600 memcpy(server->server_GUID,
601 pSMBr->u.extended_response.GUID, 16);
Jeff Laytone7ddee92008-11-14 13:44:38 -0500602 }
Jeff Laytone187e442007-10-16 17:10:44 +0000603
604 if (count == 16) {
605 server->secType = RawNTLMSSP;
Steve French254e55e2006-06-04 05:53:15 +0000606 } else {
607 rc = decode_negTokenInit(pSMBr->u.extended_response.
Jeff Layton26efa0b2010-04-24 07:57:49 -0400608 SecurityBlob, count - 16,
609 server);
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000610 if (rc == 1)
Jeff Laytone5459372007-11-03 05:11:06 +0000611 rc = 0;
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000612 else
Steve French254e55e2006-06-04 05:53:15 +0000613 rc = -EINVAL;
Shirish Pargaonkar2b149f12010-09-18 22:02:18 -0500614 if (server->secType == Kerberos) {
615 if (!server->sec_kerberos &&
616 !server->sec_mskerberos)
617 rc = -EOPNOTSUPP;
618 } else if (server->secType == RawNTLMSSP) {
619 if (!server->sec_ntlmssp)
620 rc = -EOPNOTSUPP;
621 } else
622 rc = -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 }
Steve French96daf2b2011-05-27 04:34:02 +0000624 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
Steve French07cc6cf2011-05-27 04:12:29 +0000625 rc = -EIO; /* no crypt key only if plain text pwd */
626 goto neg_err_exit;
Steve French254e55e2006-06-04 05:53:15 +0000627 } else
628 server->capabilities &= ~CAP_EXTENDED_SECURITY;
629
Steve French6344a422006-06-12 04:18:35 +0000630#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French254e55e2006-06-04 05:53:15 +0000631signing_check:
Steve French6344a422006-06-12 04:18:35 +0000632#endif
Steve French762e5ab2007-06-28 18:41:42 +0000633 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
634 /* MUST_SIGN already includes the MAY_SIGN FLAG
635 so if this is zero it means that signing is disabled */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000636 cFYI(1, "Signing disabled");
Steve French96daf2b2011-05-27 04:34:02 +0000637 if (server->sec_mode & SECMODE_SIGN_REQUIRED) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000638 cERROR(1, "Server requires "
Jeff Layton7111d212007-10-16 16:50:25 +0000639 "packet signing to be enabled in "
Joe Perchesb6b38f72010-04-21 03:50:45 +0000640 "/proc/fs/cifs/SecurityFlags.");
Steve Frenchabb63d62007-10-18 02:58:40 +0000641 rc = -EOPNOTSUPP;
642 }
Steve French96daf2b2011-05-27 04:34:02 +0000643 server->sec_mode &=
Steve French254e55e2006-06-04 05:53:15 +0000644 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Steve French762e5ab2007-06-28 18:41:42 +0000645 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
646 /* signing required */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000647 cFYI(1, "Must sign - secFlags 0x%x", secFlags);
Steve French96daf2b2011-05-27 04:34:02 +0000648 if ((server->sec_mode &
Steve French762e5ab2007-06-28 18:41:42 +0000649 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000650 cERROR(1, "signing required but server lacks support");
Jeff38c10a12007-07-06 21:10:07 +0000651 rc = -EOPNOTSUPP;
Steve French762e5ab2007-06-28 18:41:42 +0000652 } else
Steve French96daf2b2011-05-27 04:34:02 +0000653 server->sec_mode |= SECMODE_SIGN_REQUIRED;
Steve French762e5ab2007-06-28 18:41:42 +0000654 } else {
655 /* signing optional ie CIFSSEC_MAY_SIGN */
Steve French96daf2b2011-05-27 04:34:02 +0000656 if ((server->sec_mode & SECMODE_SIGN_REQUIRED) == 0)
657 server->sec_mode &=
Steve French254e55e2006-06-04 05:53:15 +0000658 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 }
Steve French50c2f752007-07-13 00:33:32 +0000660
661neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700662 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000663
Joe Perchesb6b38f72010-04-21 03:50:45 +0000664 cFYI(1, "negprot rc %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 return rc;
666}
667
668int
Pavel Shilovsky2e6e02a2012-05-25 11:11:39 +0400669CIFSSMBTDis(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670{
671 struct smb_hdr *smb_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673
Joe Perchesb6b38f72010-04-21 03:50:45 +0000674 cFYI(1, "In tree disconnect");
Jeff Laytonf1987b42008-11-15 11:12:47 -0500675
676 /* BB: do we need to check this? These should never be NULL. */
677 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
678 return -EIO;
679
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 /*
Jeff Laytonf1987b42008-11-15 11:12:47 -0500681 * No need to return error on this operation if tid invalidated and
682 * closed on server already e.g. due to tcp session crashing. Also,
683 * the tcon is no longer on the list, so no need to take lock before
684 * checking this.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 */
Steve French268875b2009-06-25 00:29:21 +0000686 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
Steve French50c2f752007-07-13 00:33:32 +0000687 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688
Steve French50c2f752007-07-13 00:33:32 +0000689 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700690 (void **)&smb_buffer);
Jeff Laytonf1987b42008-11-15 11:12:47 -0500691 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 return rc;
Steve French133672e2007-11-13 22:41:37 +0000693
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400694 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)smb_buffer, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000696 cFYI(1, "Tree disconnect failed %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697
Steve French50c2f752007-07-13 00:33:32 +0000698 /* No need to return error on this operation if tid invalidated and
Jeff Laytonf1987b42008-11-15 11:12:47 -0500699 closed on server already e.g. due to tcp session crashing */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 if (rc == -EAGAIN)
701 rc = 0;
702
703 return rc;
704}
705
Jeff Layton766fdbb2011-01-11 07:24:21 -0500706/*
707 * This is a no-op for now. We're not really interested in the reply, but
708 * rather in the fact that the server sent one and that server->lstrp
709 * gets updated.
710 *
711 * FIXME: maybe we should consider checking that the reply matches request?
712 */
713static void
714cifs_echo_callback(struct mid_q_entry *mid)
715{
716 struct TCP_Server_Info *server = mid->callback_data;
717
718 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +0400719 add_credits(server, 1, CIFS_ECHO_OP);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500720}
721
722int
723CIFSSMBEcho(struct TCP_Server_Info *server)
724{
725 ECHO_REQ *smb;
726 int rc = 0;
Jeff Laytonfcc31cb2011-05-19 16:22:53 -0400727 struct kvec iov;
Jeff Layton766fdbb2011-01-11 07:24:21 -0500728
729 cFYI(1, "In echo request");
730
731 rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
732 if (rc)
733 return rc;
734
735 /* set up echo request */
Steve French5443d132011-03-13 05:08:25 +0000736 smb->hdr.Tid = 0xffff;
Jeff Layton99d86c82011-01-20 21:19:25 -0500737 smb->hdr.WordCount = 1;
738 put_unaligned_le16(1, &smb->EchoCount);
Jeff Layton820a8032011-05-04 08:05:26 -0400739 put_bcc(1, &smb->hdr);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500740 smb->Data[0] = 'a';
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000741 inc_rfc1001_len(smb, 3);
Jeff Laytonfcc31cb2011-05-19 16:22:53 -0400742 iov.iov_base = smb;
743 iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
Jeff Layton766fdbb2011-01-11 07:24:21 -0500744
Jeff Layton44d22d82011-10-19 15:29:49 -0400745 rc = cifs_call_async(server, &iov, 1, NULL, cifs_echo_callback,
Pavel Shilovskya891f0f2012-05-23 16:14:34 +0400746 server, CIFS_ASYNC_OP | CIFS_ECHO_OP);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500747 if (rc)
748 cFYI(1, "Echo request failed: %d", rc);
749
750 cifs_small_buf_release(smb);
751
752 return rc;
753}
754
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755int
Pavel Shilovsky58c45c52012-05-25 10:54:49 +0400756CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758 LOGOFF_ANDX_REQ *pSMB;
759 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760
Joe Perchesb6b38f72010-04-21 03:50:45 +0000761 cFYI(1, "In SMBLogoff for session disconnect");
Jeff Layton14fbf502008-11-14 13:53:46 -0500762
763 /*
764 * BB: do we need to check validity of ses and server? They should
765 * always be valid since we have an active reference. If not, that
766 * should probably be a BUG()
767 */
768 if (!ses || !ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769 return -EIO;
770
Steve Frenchd7b619c2010-02-25 05:36:46 +0000771 mutex_lock(&ses->session_mutex);
Steve French3b795212008-11-13 19:45:32 +0000772 if (ses->need_reconnect)
773 goto session_already_dead; /* no need to send SMBlogoff if uid
774 already closed due to reconnect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
776 if (rc) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000777 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 return rc;
779 }
780
Pavel Shilovsky88257362012-05-23 14:01:59 +0400781 pSMB->hdr.Mid = get_next_mid(ses->server);
Steve French1982c342005-08-17 12:38:22 -0700782
Steve French96daf2b2011-05-27 04:34:02 +0000783 if (ses->server->sec_mode &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
785 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786
787 pSMB->hdr.Uid = ses->Suid;
788
789 pSMB->AndXCommand = 0xFF;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400790 rc = SendReceiveNoRsp(xid, ses, (char *) pSMB, 0);
Steve French3b795212008-11-13 19:45:32 +0000791session_already_dead:
Steve Frenchd7b619c2010-02-25 05:36:46 +0000792 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793
794 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000795 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 error */
797 if (rc == -EAGAIN)
798 rc = 0;
799 return rc;
800}
801
802int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400803CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
804 const char *fileName, __u16 type,
805 const struct nls_table *nls_codepage, int remap)
Steve French2d785a52007-07-15 01:48:57 +0000806{
807 TRANSACTION2_SPI_REQ *pSMB = NULL;
808 TRANSACTION2_SPI_RSP *pSMBr = NULL;
809 struct unlink_psx_rq *pRqD;
810 int name_len;
811 int rc = 0;
812 int bytes_returned = 0;
813 __u16 params, param_offset, offset, byte_count;
814
Joe Perchesb6b38f72010-04-21 03:50:45 +0000815 cFYI(1, "In POSIX delete");
Steve French2d785a52007-07-15 01:48:57 +0000816PsxDelete:
817 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
818 (void **) &pSMBr);
819 if (rc)
820 return rc;
821
822 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
823 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -0600824 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
825 PATH_MAX, nls_codepage, remap);
Steve French2d785a52007-07-15 01:48:57 +0000826 name_len++; /* trailing null */
827 name_len *= 2;
828 } else { /* BB add path length overrun check */
829 name_len = strnlen(fileName, PATH_MAX);
830 name_len++; /* trailing null */
831 strncpy(pSMB->FileName, fileName, name_len);
832 }
833
834 params = 6 + name_len;
835 pSMB->MaxParameterCount = cpu_to_le16(2);
836 pSMB->MaxDataCount = 0; /* BB double check this with jra */
837 pSMB->MaxSetupCount = 0;
838 pSMB->Reserved = 0;
839 pSMB->Flags = 0;
840 pSMB->Timeout = 0;
841 pSMB->Reserved2 = 0;
842 param_offset = offsetof(struct smb_com_transaction2_spi_req,
843 InformationLevel) - 4;
844 offset = param_offset + params;
845
846 /* Setup pointer to Request Data (inode type) */
847 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
848 pRqD->type = cpu_to_le16(type);
849 pSMB->ParameterOffset = cpu_to_le16(param_offset);
850 pSMB->DataOffset = cpu_to_le16(offset);
851 pSMB->SetupCount = 1;
852 pSMB->Reserved3 = 0;
853 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
854 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
855
856 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
857 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
858 pSMB->ParameterCount = cpu_to_le16(params);
859 pSMB->TotalParameterCount = pSMB->ParameterCount;
860 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
861 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000862 inc_rfc1001_len(pSMB, byte_count);
Steve French2d785a52007-07-15 01:48:57 +0000863 pSMB->ByteCount = cpu_to_le16(byte_count);
864 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
865 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000866 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000867 cFYI(1, "Posix delete returned %d", rc);
Steve French2d785a52007-07-15 01:48:57 +0000868 cifs_buf_release(pSMB);
869
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400870 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve French2d785a52007-07-15 01:48:57 +0000871
872 if (rc == -EAGAIN)
873 goto PsxDelete;
874
875 return rc;
876}
877
878int
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700879CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
880 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881{
882 DELETE_FILE_REQ *pSMB = NULL;
883 DELETE_FILE_RSP *pSMBr = NULL;
884 int rc = 0;
885 int bytes_returned;
886 int name_len;
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700887 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888
889DelFileRetry:
890 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
891 (void **) &pSMBr);
892 if (rc)
893 return rc;
894
895 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700896 name_len = cifsConvertToUTF16((__le16 *) pSMB->fileName, name,
897 PATH_MAX, cifs_sb->local_nls,
898 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899 name_len++; /* trailing null */
900 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700901 } else { /* BB improve check for buffer overruns BB */
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700902 name_len = strnlen(name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 name_len++; /* trailing null */
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700904 strncpy(pSMB->fileName, name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 }
906 pSMB->SearchAttributes =
907 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
908 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000909 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 pSMB->ByteCount = cpu_to_le16(name_len + 1);
911 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
912 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400913 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000914 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000915 cFYI(1, "Error in RMFile = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916
917 cifs_buf_release(pSMB);
918 if (rc == -EAGAIN)
919 goto DelFileRetry;
920
921 return rc;
922}
923
924int
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400925CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
926 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927{
928 DELETE_DIRECTORY_REQ *pSMB = NULL;
929 DELETE_DIRECTORY_RSP *pSMBr = NULL;
930 int rc = 0;
931 int bytes_returned;
932 int name_len;
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400933 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934
Joe Perchesb6b38f72010-04-21 03:50:45 +0000935 cFYI(1, "In CIFSSMBRmDir");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936RmDirRetry:
937 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
938 (void **) &pSMBr);
939 if (rc)
940 return rc;
941
942 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400943 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
944 PATH_MAX, cifs_sb->local_nls,
945 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946 name_len++; /* trailing null */
947 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700948 } else { /* BB improve check for buffer overruns BB */
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400949 name_len = strnlen(name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950 name_len++; /* trailing null */
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400951 strncpy(pSMB->DirName, name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952 }
953
954 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000955 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956 pSMB->ByteCount = cpu_to_le16(name_len + 1);
957 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
958 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400959 cifs_stats_inc(&tcon->stats.cifs_stats.num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000960 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000961 cFYI(1, "Error in RMDir = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962
963 cifs_buf_release(pSMB);
964 if (rc == -EAGAIN)
965 goto RmDirRetry;
966 return rc;
967}
968
969int
Pavel Shilovskyf4367202012-03-17 11:41:12 +0300970CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
971 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972{
973 int rc = 0;
974 CREATE_DIRECTORY_REQ *pSMB = NULL;
975 CREATE_DIRECTORY_RSP *pSMBr = NULL;
976 int bytes_returned;
977 int name_len;
Pavel Shilovskyf4367202012-03-17 11:41:12 +0300978 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979
Joe Perchesb6b38f72010-04-21 03:50:45 +0000980 cFYI(1, "In CIFSSMBMkDir");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981MkDirRetry:
982 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
983 (void **) &pSMBr);
984 if (rc)
985 return rc;
986
987 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -0600988 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
Pavel Shilovskyf4367202012-03-17 11:41:12 +0300989 PATH_MAX, cifs_sb->local_nls,
990 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991 name_len++; /* trailing null */
992 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700993 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 name_len = strnlen(name, PATH_MAX);
995 name_len++; /* trailing null */
996 strncpy(pSMB->DirName, name, name_len);
997 }
998
999 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001000 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001 pSMB->ByteCount = cpu_to_le16(name_len + 1);
1002 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1003 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001004 cifs_stats_inc(&tcon->stats.cifs_stats.num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +00001005 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001006 cFYI(1, "Error in Mkdir = %d", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07001007
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 cifs_buf_release(pSMB);
1009 if (rc == -EAGAIN)
1010 goto MkDirRetry;
1011 return rc;
1012}
1013
Steve French2dd29d32007-04-23 22:07:35 +00001014int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001015CIFSPOSIXCreate(const unsigned int xid, struct cifs_tcon *tcon,
1016 __u32 posix_flags, __u64 mode, __u16 *netfid,
1017 FILE_UNIX_BASIC_INFO *pRetData, __u32 *pOplock,
1018 const char *name, const struct nls_table *nls_codepage,
1019 int remap)
Steve French2dd29d32007-04-23 22:07:35 +00001020{
1021 TRANSACTION2_SPI_REQ *pSMB = NULL;
1022 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1023 int name_len;
1024 int rc = 0;
1025 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001026 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +00001027 OPEN_PSX_REQ *pdata;
1028 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +00001029
Joe Perchesb6b38f72010-04-21 03:50:45 +00001030 cFYI(1, "In POSIX Create");
Steve French2dd29d32007-04-23 22:07:35 +00001031PsxCreat:
1032 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1033 (void **) &pSMBr);
1034 if (rc)
1035 return rc;
1036
1037 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1038 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001039 cifsConvertToUTF16((__le16 *) pSMB->FileName, name,
1040 PATH_MAX, nls_codepage, remap);
Steve French2dd29d32007-04-23 22:07:35 +00001041 name_len++; /* trailing null */
1042 name_len *= 2;
1043 } else { /* BB improve the check for buffer overruns BB */
1044 name_len = strnlen(name, PATH_MAX);
1045 name_len++; /* trailing null */
1046 strncpy(pSMB->FileName, name, name_len);
1047 }
1048
1049 params = 6 + name_len;
1050 count = sizeof(OPEN_PSX_REQ);
1051 pSMB->MaxParameterCount = cpu_to_le16(2);
1052 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1053 pSMB->MaxSetupCount = 0;
1054 pSMB->Reserved = 0;
1055 pSMB->Flags = 0;
1056 pSMB->Timeout = 0;
1057 pSMB->Reserved2 = 0;
1058 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001059 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001060 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001061 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001062 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001063 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001064 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001065 pdata->OpenFlags = cpu_to_le32(*pOplock);
1066 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1067 pSMB->DataOffset = cpu_to_le16(offset);
1068 pSMB->SetupCount = 1;
1069 pSMB->Reserved3 = 0;
1070 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1071 byte_count = 3 /* pad */ + params + count;
1072
1073 pSMB->DataCount = cpu_to_le16(count);
1074 pSMB->ParameterCount = cpu_to_le16(params);
1075 pSMB->TotalDataCount = pSMB->DataCount;
1076 pSMB->TotalParameterCount = pSMB->ParameterCount;
1077 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1078 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001079 inc_rfc1001_len(pSMB, byte_count);
Steve French2dd29d32007-04-23 22:07:35 +00001080 pSMB->ByteCount = cpu_to_le16(byte_count);
1081 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1082 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1083 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001084 cFYI(1, "Posix create returned %d", rc);
Steve French2dd29d32007-04-23 22:07:35 +00001085 goto psx_create_err;
1086 }
1087
Joe Perchesb6b38f72010-04-21 03:50:45 +00001088 cFYI(1, "copying inode info");
Steve French2dd29d32007-04-23 22:07:35 +00001089 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1090
Jeff Layton820a8032011-05-04 08:05:26 -04001091 if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) {
Steve French2dd29d32007-04-23 22:07:35 +00001092 rc = -EIO; /* bad smb */
1093 goto psx_create_err;
1094 }
1095
1096 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001097 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001098 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001099
Steve French2dd29d32007-04-23 22:07:35 +00001100 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001101 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001102 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1103 /* Let caller know file was created so we can set the mode. */
1104 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001105 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001106 *pOplock |= CIFS_CREATE_ACTION;
1107 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001108 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1109 pRetData->Type = cpu_to_le32(-1); /* unknown */
Joe Perchesb6b38f72010-04-21 03:50:45 +00001110 cFYI(DBG2, "unknown type");
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001111 } else {
Jeff Layton820a8032011-05-04 08:05:26 -04001112 if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001113 + sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001114 cERROR(1, "Open response data too small");
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001115 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001116 goto psx_create_err;
1117 }
Steve French50c2f752007-07-13 00:33:32 +00001118 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001119 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001120 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001121 }
Steve French2dd29d32007-04-23 22:07:35 +00001122
1123psx_create_err:
1124 cifs_buf_release(pSMB);
1125
Steve French65bc98b2009-07-10 15:27:25 +00001126 if (posix_flags & SMB_O_DIRECTORY)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001127 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixmkdirs);
Steve French65bc98b2009-07-10 15:27:25 +00001128 else
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001129 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixopens);
Steve French2dd29d32007-04-23 22:07:35 +00001130
1131 if (rc == -EAGAIN)
1132 goto PsxCreat;
1133
Steve French50c2f752007-07-13 00:33:32 +00001134 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001135}
1136
Steve Frencha9d02ad2005-08-24 23:06:05 -07001137static __u16 convert_disposition(int disposition)
1138{
1139 __u16 ofun = 0;
1140
1141 switch (disposition) {
1142 case FILE_SUPERSEDE:
1143 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1144 break;
1145 case FILE_OPEN:
1146 ofun = SMBOPEN_OAPPEND;
1147 break;
1148 case FILE_CREATE:
1149 ofun = SMBOPEN_OCREATE;
1150 break;
1151 case FILE_OPEN_IF:
1152 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1153 break;
1154 case FILE_OVERWRITE:
1155 ofun = SMBOPEN_OTRUNC;
1156 break;
1157 case FILE_OVERWRITE_IF:
1158 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1159 break;
1160 default:
Joe Perchesb6b38f72010-04-21 03:50:45 +00001161 cFYI(1, "unknown disposition %d", disposition);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001162 ofun = SMBOPEN_OAPPEND; /* regular open */
1163 }
1164 return ofun;
1165}
1166
Jeff Layton35fc37d2008-05-14 10:22:03 -07001167static int
1168access_flags_to_smbopen_mode(const int access_flags)
1169{
1170 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1171
1172 if (masked_flags == GENERIC_READ)
1173 return SMBOPEN_READ;
1174 else if (masked_flags == GENERIC_WRITE)
1175 return SMBOPEN_WRITE;
1176
1177 /* just go for read/write */
1178 return SMBOPEN_READWRITE;
1179}
1180
Steve Frencha9d02ad2005-08-24 23:06:05 -07001181int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001182SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001183 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001184 const int access_flags, const int create_options, __u16 *netfid,
1185 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001186 const struct nls_table *nls_codepage, int remap)
1187{
1188 int rc = -EACCES;
1189 OPENX_REQ *pSMB = NULL;
1190 OPENX_RSP *pSMBr = NULL;
1191 int bytes_returned;
1192 int name_len;
1193 __u16 count;
1194
1195OldOpenRetry:
1196 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1197 (void **) &pSMBr);
1198 if (rc)
1199 return rc;
1200
1201 pSMB->AndXCommand = 0xFF; /* none */
1202
1203 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1204 count = 1; /* account for one byte pad to word boundary */
1205 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001206 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1207 fileName, PATH_MAX, nls_codepage, remap);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001208 name_len++; /* trailing null */
1209 name_len *= 2;
1210 } else { /* BB improve check for buffer overruns BB */
1211 count = 0; /* no pad */
1212 name_len = strnlen(fileName, PATH_MAX);
1213 name_len++; /* trailing null */
1214 strncpy(pSMB->fileName, fileName, name_len);
1215 }
1216 if (*pOplock & REQ_OPLOCK)
1217 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001218 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001219 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001220
Steve Frencha9d02ad2005-08-24 23:06:05 -07001221 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001222 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001223 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1224 /* set file as system file if special file such
1225 as fifo and server expecting SFU style and
1226 no Unix extensions */
1227
Steve French790fe572007-07-07 19:25:05 +00001228 if (create_options & CREATE_OPTION_SPECIAL)
1229 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001230 else /* BB FIXME BB */
1231 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001232
Jeff Layton67750fb2008-05-09 22:28:02 +00001233 if (create_options & CREATE_OPTION_READONLY)
1234 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001235
1236 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001237/* pSMB->CreateOptions = cpu_to_le32(create_options &
1238 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001239 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001240
1241 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001242 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001243 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001244 inc_rfc1001_len(pSMB, count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001245
1246 pSMB->ByteCount = cpu_to_le16(count);
1247 /* long_op set to 1 to allow for oplock break timeouts */
1248 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001249 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001250 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001251 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001252 cFYI(1, "Error in Open = %d", rc);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001253 } else {
1254 /* BB verify if wct == 15 */
1255
Steve French582d21e2008-05-13 04:54:12 +00001256/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001257
1258 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1259 /* Let caller know file was created so we can set the mode. */
1260 /* Do we care about the CreateAction in any other cases? */
1261 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001262/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001263 *pOplock |= CIFS_CREATE_ACTION; */
1264 /* BB FIXME END */
1265
Steve French790fe572007-07-07 19:25:05 +00001266 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001267 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1268 pfile_info->LastAccessTime = 0; /* BB fixme */
1269 pfile_info->LastWriteTime = 0; /* BB fixme */
1270 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001271 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001272 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001273 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001274 pfile_info->AllocationSize =
1275 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1276 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001277 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001278 pfile_info->DeletePending = 0;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001279 }
1280 }
1281
1282 cifs_buf_release(pSMB);
1283 if (rc == -EAGAIN)
1284 goto OldOpenRetry;
1285 return rc;
1286}
1287
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001289CIFSSMBOpen(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001291 const int access_flags, const int create_options, __u16 *netfid,
1292 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001293 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294{
1295 int rc = -EACCES;
1296 OPEN_REQ *pSMB = NULL;
1297 OPEN_RSP *pSMBr = NULL;
1298 int bytes_returned;
1299 int name_len;
1300 __u16 count;
1301
1302openRetry:
1303 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1304 (void **) &pSMBr);
1305 if (rc)
1306 return rc;
1307
1308 pSMB->AndXCommand = 0xFF; /* none */
1309
1310 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1311 count = 1; /* account for one byte pad to word boundary */
1312 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001313 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1314 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315 name_len++; /* trailing null */
1316 name_len *= 2;
1317 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001318 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319 count = 0; /* no pad */
1320 name_len = strnlen(fileName, PATH_MAX);
1321 name_len++; /* trailing null */
1322 pSMB->NameLength = cpu_to_le16(name_len);
1323 strncpy(pSMB->fileName, fileName, name_len);
1324 }
1325 if (*pOplock & REQ_OPLOCK)
1326 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001327 else if (*pOplock & REQ_BATCHOPLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1330 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -07001331 /* set file as system file if special file such
1332 as fifo and server expecting SFU style and
1333 no Unix extensions */
Steve French790fe572007-07-07 19:25:05 +00001334 if (create_options & CREATE_OPTION_SPECIAL)
Steve Frencheda3c0292005-07-21 15:20:28 -07001335 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1336 else
1337 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Jeff Layton67750fb2008-05-09 22:28:02 +00001338
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339 /* XP does not handle ATTR_POSIX_SEMANTICS */
1340 /* but it helps speed up case sensitive checks for other
1341 servers such as Samba */
1342 if (tcon->ses->capabilities & CAP_UNIX)
1343 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1344
Jeff Layton67750fb2008-05-09 22:28:02 +00001345 if (create_options & CREATE_OPTION_READONLY)
1346 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1347
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1349 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -07001350 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001351 /* BB Expirement with various impersonation levels and verify */
1352 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353 pSMB->SecurityFlags =
1354 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1355
1356 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001357 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358
1359 pSMB->ByteCount = cpu_to_le16(count);
1360 /* long_op set to 1 to allow for oplock break timeouts */
1361 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001362 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001363 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001364 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001365 cFYI(1, "Error in Open = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366 } else {
Steve French09d1db52005-04-28 22:41:08 -07001367 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1369 /* Let caller know file was created so we can set the mode. */
1370 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001371 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve French50c2f752007-07-13 00:33:32 +00001372 *pOplock |= CIFS_CREATE_ACTION;
Steve French790fe572007-07-07 19:25:05 +00001373 if (pfile_info) {
Steve French61e74802008-12-03 00:57:54 +00001374 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1375 36 /* CreationTime to Attributes */);
1376 /* the file_info buf is endian converted by caller */
1377 pfile_info->AllocationSize = pSMBr->AllocationSize;
1378 pfile_info->EndOfFile = pSMBr->EndOfFile;
1379 pfile_info->NumberOfLinks = cpu_to_le32(1);
1380 pfile_info->DeletePending = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001383
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384 cifs_buf_release(pSMB);
1385 if (rc == -EAGAIN)
1386 goto openRetry;
1387 return rc;
1388}
1389
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001390/*
1391 * Discard any remaining data in the current SMB. To do this, we borrow the
1392 * current bigbuf.
1393 */
1394static int
1395cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1396{
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001397 unsigned int rfclen = get_rfc1002_length(server->smallbuf);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001398 int remaining = rfclen + 4 - server->total_read;
1399 struct cifs_readdata *rdata = mid->callback_data;
1400
1401 while (remaining > 0) {
1402 int length;
1403
1404 length = cifs_read_from_socket(server, server->bigbuf,
1405 min_t(unsigned int, remaining,
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001406 CIFSMaxBufSize + MAX_HEADER_SIZE(server)));
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001407 if (length < 0)
1408 return length;
1409 server->total_read += length;
1410 remaining -= length;
1411 }
1412
1413 dequeue_mid(mid, rdata->result);
1414 return 0;
1415}
1416
Pavel Shilovsky09a47072012-09-18 16:20:29 -07001417int
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001418cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1419{
1420 int length, len;
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001421 unsigned int data_offset, data_len;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001422 struct cifs_readdata *rdata = mid->callback_data;
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001423 char *buf = server->smallbuf;
1424 unsigned int buflen = get_rfc1002_length(buf) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001425
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001426 cFYI(1, "%s: mid=%llu offset=%llu bytes=%u", __func__,
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001427 mid->mid, rdata->offset, rdata->bytes);
1428
1429 /*
1430 * read the rest of READ_RSP header (sans Data array), or whatever we
1431 * can if there's not enough data. At this point, we've read down to
1432 * the Mid.
1433 */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001434 len = min_t(unsigned int, buflen, server->vals->read_rsp_size) -
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001435 HEADER_SIZE(server) + 1;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001436
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001437 rdata->iov[0].iov_base = buf + HEADER_SIZE(server) - 1;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001438 rdata->iov[0].iov_len = len;
1439
1440 length = cifs_readv_from_socket(server, rdata->iov, 1, len);
1441 if (length < 0)
1442 return length;
1443 server->total_read += length;
1444
1445 /* Was the SMB read successful? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001446 rdata->result = server->ops->map_error(buf, false);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001447 if (rdata->result != 0) {
1448 cFYI(1, "%s: server returned error %d", __func__,
1449 rdata->result);
1450 return cifs_readv_discard(server, mid);
1451 }
1452
1453 /* Is there enough to get to the rest of the READ_RSP header? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001454 if (server->total_read < server->vals->read_rsp_size) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001455 cFYI(1, "%s: server returned short header. got=%u expected=%zu",
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001456 __func__, server->total_read,
1457 server->vals->read_rsp_size);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001458 rdata->result = -EIO;
1459 return cifs_readv_discard(server, mid);
1460 }
1461
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001462 data_offset = server->ops->read_data_offset(buf) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001463 if (data_offset < server->total_read) {
1464 /*
1465 * win2k8 sometimes sends an offset of 0 when the read
1466 * is beyond the EOF. Treat it as if the data starts just after
1467 * the header.
1468 */
1469 cFYI(1, "%s: data offset (%u) inside read response header",
1470 __func__, data_offset);
1471 data_offset = server->total_read;
1472 } else if (data_offset > MAX_CIFS_SMALL_BUFFER_SIZE) {
1473 /* data_offset is beyond the end of smallbuf */
1474 cFYI(1, "%s: data offset (%u) beyond end of smallbuf",
1475 __func__, data_offset);
1476 rdata->result = -EIO;
1477 return cifs_readv_discard(server, mid);
1478 }
1479
1480 cFYI(1, "%s: total_read=%u data_offset=%u", __func__,
1481 server->total_read, data_offset);
1482
1483 len = data_offset - server->total_read;
1484 if (len > 0) {
1485 /* read any junk before data into the rest of smallbuf */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001486 rdata->iov[0].iov_base = buf + server->total_read;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001487 rdata->iov[0].iov_len = len;
1488 length = cifs_readv_from_socket(server, rdata->iov, 1, len);
1489 if (length < 0)
1490 return length;
1491 server->total_read += length;
1492 }
1493
1494 /* set up first iov for signature check */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001495 rdata->iov[0].iov_base = buf;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001496 rdata->iov[0].iov_len = server->total_read;
1497 cFYI(1, "0: iov_base=%p iov_len=%zu",
1498 rdata->iov[0].iov_base, rdata->iov[0].iov_len);
1499
1500 /* how much data is in the response? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001501 data_len = server->ops->read_data_length(buf);
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001502 if (data_offset + data_len > buflen) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001503 /* data_len is corrupt -- discard frame */
1504 rdata->result = -EIO;
1505 return cifs_readv_discard(server, mid);
1506 }
1507
1508 /* marshal up the page array */
Jeff Layton3cf003c2012-07-11 09:09:36 -04001509 cifs_kmap_lock();
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001510 len = rdata->marshal_iov(rdata, data_len);
Jeff Layton3cf003c2012-07-11 09:09:36 -04001511 cifs_kmap_unlock();
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001512 data_len -= len;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001513
1514 /* issue the read if we have any iovecs left to fill */
1515 if (rdata->nr_iov > 1) {
1516 length = cifs_readv_from_socket(server, &rdata->iov[1],
1517 rdata->nr_iov - 1, len);
1518 if (length < 0)
1519 return length;
1520 server->total_read += length;
1521 } else {
1522 length = 0;
1523 }
1524
1525 rdata->bytes = length;
1526
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001527 cFYI(1, "total_read=%u buflen=%u remaining=%u", server->total_read,
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001528 buflen, data_len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001529
1530 /* discard anything left over */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001531 if (server->total_read < buflen)
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001532 return cifs_readv_discard(server, mid);
1533
1534 dequeue_mid(mid, false);
1535 return length;
1536}
1537
1538static void
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001539cifs_readv_callback(struct mid_q_entry *mid)
1540{
1541 struct cifs_readdata *rdata = mid->callback_data;
1542 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1543 struct TCP_Server_Info *server = tcon->ses->server;
1544
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001545 cFYI(1, "%s: mid=%llu state=%d result=%d bytes=%u", __func__,
1546 mid->mid, mid->mid_state, rdata->result, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001547
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001548 switch (mid->mid_state) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001549 case MID_RESPONSE_RECEIVED:
1550 /* result already set, check signature */
1551 if (server->sec_mode &
1552 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
Steve French985e4ff02012-08-03 09:42:45 -05001553 int rc = 0;
1554
1555 rc = cifs_verify_signature(rdata->iov, rdata->nr_iov,
1556 server,
1557 mid->sequence_number + 1);
1558 if (rc)
1559 cERROR(1, "SMB signature verification returned "
1560 "error = %d", rc);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001561 }
1562 /* FIXME: should this be counted toward the initiating task? */
1563 task_io_account_read(rdata->bytes);
1564 cifs_stats_bytes_read(tcon, rdata->bytes);
1565 break;
1566 case MID_REQUEST_SUBMITTED:
1567 case MID_RETRY_NEEDED:
1568 rdata->result = -EAGAIN;
1569 break;
1570 default:
1571 rdata->result = -EIO;
1572 }
1573
Jeff Laytonda472fc2012-03-23 14:40:53 -04001574 queue_work(cifsiod_wq, &rdata->work);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001575 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04001576 add_credits(server, 1, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001577}
1578
1579/* cifs_async_readv - send an async write, and set up mid to handle result */
1580int
1581cifs_async_readv(struct cifs_readdata *rdata)
1582{
1583 int rc;
1584 READ_REQ *smb = NULL;
1585 int wct;
1586 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1587
1588 cFYI(1, "%s: offset=%llu bytes=%u", __func__,
1589 rdata->offset, rdata->bytes);
1590
1591 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1592 wct = 12;
1593 else {
1594 wct = 10; /* old style read */
1595 if ((rdata->offset >> 32) > 0) {
1596 /* can not handle this big offset for old */
1597 return -EIO;
1598 }
1599 }
1600
1601 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **)&smb);
1602 if (rc)
1603 return rc;
1604
1605 smb->hdr.Pid = cpu_to_le16((__u16)rdata->pid);
1606 smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16));
1607
1608 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07001609 smb->Fid = rdata->cfile->fid.netfid;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001610 smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF);
1611 if (wct == 12)
1612 smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32);
1613 smb->Remaining = 0;
1614 smb->MaxCount = cpu_to_le16(rdata->bytes & 0xFFFF);
1615 smb->MaxCountHigh = cpu_to_le32(rdata->bytes >> 16);
1616 if (wct == 12)
1617 smb->ByteCount = 0;
1618 else {
1619 /* old style read */
1620 struct smb_com_readx_req *smbr =
1621 (struct smb_com_readx_req *)smb;
1622 smbr->ByteCount = 0;
1623 }
1624
1625 /* 4 for RFC1001 length + 1 for BCC */
1626 rdata->iov[0].iov_base = smb;
1627 rdata->iov[0].iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
1628
Jeff Layton6993f742012-05-16 07:13:17 -04001629 kref_get(&rdata->refcount);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001630 rc = cifs_call_async(tcon->ses->server, rdata->iov, 1,
1631 cifs_readv_receive, cifs_readv_callback,
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04001632 rdata, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001633
1634 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001635 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Jeff Layton6993f742012-05-16 07:13:17 -04001636 else
1637 kref_put(&rdata->refcount, cifs_readdata_release);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001638
1639 cifs_small_buf_release(smb);
1640 return rc;
1641}
1642
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001644CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
1645 unsigned int *nbytes, char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646{
1647 int rc = -EACCES;
1648 READ_REQ *pSMB = NULL;
1649 READ_RSP *pSMBr = NULL;
1650 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001651 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001652 int resp_buf_type = 0;
1653 struct kvec iov[1];
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001654 __u32 pid = io_parms->pid;
1655 __u16 netfid = io_parms->netfid;
1656 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001657 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001658 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001659
Joe Perchesb6b38f72010-04-21 03:50:45 +00001660 cFYI(1, "Reading %d bytes on fid %d", count, netfid);
Steve French790fe572007-07-07 19:25:05 +00001661 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001662 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001663 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001664 wct = 10; /* old style read */
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001665 if ((offset >> 32) > 0) {
Steve French4c3130e2008-12-09 00:28:16 +00001666 /* can not handle this big offset for old */
1667 return -EIO;
1668 }
1669 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670
1671 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001672 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673 if (rc)
1674 return rc;
1675
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001676 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1677 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1678
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679 /* tcon and ses pointer are checked in smb_init */
1680 if (tcon->ses->server == NULL)
1681 return -ECONNABORTED;
1682
Steve Frenchec637e32005-12-12 20:53:18 -08001683 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684 pSMB->Fid = netfid;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001685 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001686 if (wct == 12)
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001687 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001688
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689 pSMB->Remaining = 0;
1690 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1691 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001692 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001693 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1694 else {
1695 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001696 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001697 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001698 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001699 }
Steve Frenchec637e32005-12-12 20:53:18 -08001700
1701 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001702 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve Frencha761ac52007-10-18 21:45:27 +00001703 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Jeff Layton77499812011-01-11 07:24:23 -05001704 &resp_buf_type, CIFS_LOG_ERROR);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001705 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001706 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001708 cERROR(1, "Send error in read = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709 } else {
1710 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1711 data_length = data_length << 16;
1712 data_length += le16_to_cpu(pSMBr->DataLength);
1713 *nbytes = data_length;
1714
1715 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001716 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717 || (data_length > count)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001718 cFYI(1, "bad length %d for count %d",
1719 data_length, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720 rc = -EIO;
1721 *nbytes = 0;
1722 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001723 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001724 le16_to_cpu(pSMBr->DataOffset);
1725/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001726 cERROR(1, "Faulting on read rc = %d",rc);
Steve French50c2f752007-07-13 00:33:32 +00001727 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001728 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001729 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001730 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731 }
1732 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733
Steve French4b8f9302006-02-26 16:41:18 +00001734/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001735 if (*buf) {
1736 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001737 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001738 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001739 cifs_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001740 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001741 /* return buffer to caller to free */
1742 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001743 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001744 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001745 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001746 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001747 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001748
1749 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750 since file handle passed in no longer valid */
1751 return rc;
1752}
1753
Steve Frenchec637e32005-12-12 20:53:18 -08001754
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001756CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001757 unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001758 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759{
1760 int rc = -EACCES;
1761 WRITE_REQ *pSMB = NULL;
1762 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001763 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001764 __u32 bytes_sent;
1765 __u16 byte_count;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001766 __u32 pid = io_parms->pid;
1767 __u16 netfid = io_parms->netfid;
1768 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001769 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001770 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771
Steve Frencha24e2d72010-04-03 17:20:21 +00001772 *nbytes = 0;
1773
Joe Perchesb6b38f72010-04-21 03:50:45 +00001774 /* cFYI(1, "write at %lld %d bytes", offset, count);*/
Steve French790fe572007-07-07 19:25:05 +00001775 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001776 return -ECONNABORTED;
1777
Steve French790fe572007-07-07 19:25:05 +00001778 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001779 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001780 else {
Steve French1c955182005-08-30 20:58:07 -07001781 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001782 if ((offset >> 32) > 0) {
1783 /* can not handle big offset for old srv */
1784 return -EIO;
1785 }
1786 }
Steve French1c955182005-08-30 20:58:07 -07001787
1788 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001789 (void **) &pSMBr);
1790 if (rc)
1791 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001792
1793 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1794 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1795
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796 /* tcon and ses pointer are checked in smb_init */
1797 if (tcon->ses->server == NULL)
1798 return -ECONNABORTED;
1799
1800 pSMB->AndXCommand = 0xFF; /* none */
1801 pSMB->Fid = netfid;
1802 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001803 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001804 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001805
Linus Torvalds1da177e2005-04-16 15:20:36 -07001806 pSMB->Reserved = 0xFFFFFFFF;
1807 pSMB->WriteMode = 0;
1808 pSMB->Remaining = 0;
1809
Steve French50c2f752007-07-13 00:33:32 +00001810 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811 can send more if LARGE_WRITE_X capability returned by the server and if
1812 our buffer is big enough or if we convert to iovecs on socket writes
1813 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001814 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1816 } else {
1817 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1818 & ~0xFF;
1819 }
1820
1821 if (bytes_sent > count)
1822 bytes_sent = count;
1823 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001824 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001825 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001826 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001827 else if (ubuf) {
1828 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001829 cifs_buf_release(pSMB);
1830 return -EFAULT;
1831 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001832 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001833 /* No buffer */
1834 cifs_buf_release(pSMB);
1835 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001836 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001837 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001838 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001839 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001840 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001841
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1843 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001844 inc_rfc1001_len(pSMB, byte_count);
Steve French1c955182005-08-30 20:58:07 -07001845
Steve French790fe572007-07-07 19:25:05 +00001846 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001847 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001848 else { /* old style write has byte count 4 bytes earlier
1849 so 4 bytes pad */
1850 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001851 (struct smb_com_writex_req *)pSMB;
1852 pSMBW->ByteCount = cpu_to_le16(byte_count);
1853 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854
1855 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1856 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001857 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00001859 cFYI(1, "Send error in write = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860 } else {
1861 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1862 *nbytes = (*nbytes) << 16;
1863 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301864
1865 /*
1866 * Mask off high 16 bits when bytes written as returned by the
1867 * server is greater than bytes requested by the client. Some
1868 * OS/2 servers are known to set incorrect CountHigh values.
1869 */
1870 if (*nbytes > count)
1871 *nbytes &= 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872 }
1873
1874 cifs_buf_release(pSMB);
1875
Steve French50c2f752007-07-13 00:33:32 +00001876 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001877 since file handle passed in no longer valid */
1878
1879 return rc;
1880}
1881
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001882void
1883cifs_writedata_release(struct kref *refcount)
1884{
1885 struct cifs_writedata *wdata = container_of(refcount,
1886 struct cifs_writedata, refcount);
1887
1888 if (wdata->cfile)
1889 cifsFileInfo_put(wdata->cfile);
1890
1891 kfree(wdata);
1892}
1893
1894/*
1895 * Write failed with a retryable error. Resend the write request. It's also
1896 * possible that the page was redirtied so re-clean the page.
1897 */
1898static void
1899cifs_writev_requeue(struct cifs_writedata *wdata)
1900{
1901 int i, rc;
1902 struct inode *inode = wdata->cfile->dentry->d_inode;
Pavel Shilovskyc9de5c82012-09-18 16:20:29 -07001903 struct TCP_Server_Info *server;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001904
1905 for (i = 0; i < wdata->nr_pages; i++) {
1906 lock_page(wdata->pages[i]);
1907 clear_page_dirty_for_io(wdata->pages[i]);
1908 }
1909
1910 do {
Pavel Shilovskyc9de5c82012-09-18 16:20:29 -07001911 server = tlink_tcon(wdata->cfile->tlink)->ses->server;
1912 rc = server->ops->async_writev(wdata);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001913 } while (rc == -EAGAIN);
1914
1915 for (i = 0; i < wdata->nr_pages; i++) {
1916 if (rc != 0)
1917 SetPageError(wdata->pages[i]);
1918 unlock_page(wdata->pages[i]);
1919 }
1920
1921 mapping_set_error(inode->i_mapping, rc);
1922 kref_put(&wdata->refcount, cifs_writedata_release);
1923}
1924
Jeff Laytonc2e87642012-03-23 14:40:55 -04001925void
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001926cifs_writev_complete(struct work_struct *work)
1927{
1928 struct cifs_writedata *wdata = container_of(work,
1929 struct cifs_writedata, work);
1930 struct inode *inode = wdata->cfile->dentry->d_inode;
1931 int i = 0;
1932
1933 if (wdata->result == 0) {
Jeff Layton597b0272012-03-23 14:40:56 -04001934 spin_lock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001935 cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
Jeff Layton597b0272012-03-23 14:40:56 -04001936 spin_unlock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001937 cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
1938 wdata->bytes);
1939 } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
1940 return cifs_writev_requeue(wdata);
1941
1942 for (i = 0; i < wdata->nr_pages; i++) {
1943 struct page *page = wdata->pages[i];
1944 if (wdata->result == -EAGAIN)
1945 __set_page_dirty_nobuffers(page);
1946 else if (wdata->result < 0)
1947 SetPageError(page);
1948 end_page_writeback(page);
1949 page_cache_release(page);
1950 }
1951 if (wdata->result != -EAGAIN)
1952 mapping_set_error(inode->i_mapping, wdata->result);
1953 kref_put(&wdata->refcount, cifs_writedata_release);
1954}
1955
1956struct cifs_writedata *
Jeff Laytonc2e87642012-03-23 14:40:55 -04001957cifs_writedata_alloc(unsigned int nr_pages, work_func_t complete)
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001958{
1959 struct cifs_writedata *wdata;
1960
1961 /* this would overflow */
1962 if (nr_pages == 0) {
1963 cERROR(1, "%s: called with nr_pages == 0!", __func__);
1964 return NULL;
1965 }
1966
1967 /* writedata + number of page pointers */
1968 wdata = kzalloc(sizeof(*wdata) +
1969 sizeof(struct page *) * (nr_pages - 1), GFP_NOFS);
1970 if (wdata != NULL) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001971 kref_init(&wdata->refcount);
Jeff Laytonda82f7e2012-03-23 14:40:56 -04001972 INIT_LIST_HEAD(&wdata->list);
1973 init_completion(&wdata->done);
1974 INIT_WORK(&wdata->work, complete);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001975 }
1976 return wdata;
1977}
1978
1979/*
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001980 * Check the mid_state and signature on received buffer (if any), and queue the
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001981 * workqueue completion task.
1982 */
1983static void
1984cifs_writev_callback(struct mid_q_entry *mid)
1985{
1986 struct cifs_writedata *wdata = mid->callback_data;
Steve French96daf2b2011-05-27 04:34:02 +00001987 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001988 unsigned int written;
1989 WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
1990
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001991 switch (mid->mid_state) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001992 case MID_RESPONSE_RECEIVED:
1993 wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
1994 if (wdata->result != 0)
1995 break;
1996
1997 written = le16_to_cpu(smb->CountHigh);
1998 written <<= 16;
1999 written += le16_to_cpu(smb->Count);
2000 /*
2001 * Mask off high 16 bits when bytes written as returned
2002 * by the server is greater than bytes requested by the
2003 * client. OS/2 servers are known to set incorrect
2004 * CountHigh values.
2005 */
2006 if (written > wdata->bytes)
2007 written &= 0xFFFF;
2008
2009 if (written < wdata->bytes)
2010 wdata->result = -ENOSPC;
2011 else
2012 wdata->bytes = written;
2013 break;
2014 case MID_REQUEST_SUBMITTED:
2015 case MID_RETRY_NEEDED:
2016 wdata->result = -EAGAIN;
2017 break;
2018 default:
2019 wdata->result = -EIO;
2020 break;
2021 }
2022
Jeff Laytonda472fc2012-03-23 14:40:53 -04002023 queue_work(cifsiod_wq, &wdata->work);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002024 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002025 add_credits(tcon->ses->server, 1, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002026}
2027
2028/* cifs_async_writev - send an async write, and set up mid to handle result */
2029int
2030cifs_async_writev(struct cifs_writedata *wdata)
2031{
2032 int i, rc = -EACCES;
2033 WRITE_REQ *smb = NULL;
2034 int wct;
Steve French96daf2b2011-05-27 04:34:02 +00002035 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002036 struct kvec *iov = NULL;
2037
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
2052 /* 1 iov per page + 1 for header */
2053 iov = kzalloc((wdata->nr_pages + 1) * sizeof(*iov), GFP_NOFS);
2054 if (iov == NULL) {
2055 rc = -ENOMEM;
2056 goto async_writev_out;
2057 }
2058
Jeff Laytonfe5f5d22012-03-23 14:40:55 -04002059 smb->hdr.Pid = cpu_to_le16((__u16)wdata->pid);
2060 smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16));
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002061
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002062 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07002063 smb->Fid = wdata->cfile->fid.netfid;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002064 smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
2065 if (wct == 14)
2066 smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
2067 smb->Reserved = 0xFFFFFFFF;
2068 smb->WriteMode = 0;
2069 smb->Remaining = 0;
2070
2071 smb->DataOffset =
2072 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
2073
2074 /* 4 for RFC1001 length + 1 for BCC */
2075 iov[0].iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4 + 1;
2076 iov[0].iov_base = smb;
2077
Jeff Laytone9492872012-03-23 14:40:56 -04002078 /*
2079 * This function should marshal up the page array into the kvec
2080 * array, reserving [0] for the header. It should kmap the pages
2081 * and set the iov_len properly for each one. It may also set
2082 * wdata->bytes too.
2083 */
Jeff Layton3cf003c2012-07-11 09:09:36 -04002084 cifs_kmap_lock();
Jeff Laytone9492872012-03-23 14:40:56 -04002085 wdata->marshal_iov(iov, wdata);
Jeff Layton3cf003c2012-07-11 09:09:36 -04002086 cifs_kmap_unlock();
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002087
2088 cFYI(1, "async write at %llu %u bytes", wdata->offset, wdata->bytes);
2089
2090 smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
2091 smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16);
2092
2093 if (wct == 14) {
2094 inc_rfc1001_len(&smb->hdr, wdata->bytes + 1);
2095 put_bcc(wdata->bytes + 1, &smb->hdr);
2096 } else {
2097 /* wct == 12 */
2098 struct smb_com_writex_req *smbw =
2099 (struct smb_com_writex_req *)smb;
2100 inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
2101 put_bcc(wdata->bytes + 5, &smbw->hdr);
2102 iov[0].iov_len += 4; /* pad bigger by four bytes */
2103 }
2104
2105 kref_get(&wdata->refcount);
2106 rc = cifs_call_async(tcon->ses->server, iov, wdata->nr_pages + 1,
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002107 NULL, cifs_writev_callback, wdata, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002108
2109 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002110 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002111 else
2112 kref_put(&wdata->refcount, cifs_writedata_release);
2113
2114 /* send is done, unmap pages */
2115 for (i = 0; i < wdata->nr_pages; i++)
2116 kunmap(wdata->pages[i]);
2117
2118async_writev_out:
2119 cifs_small_buf_release(smb);
2120 kfree(iov);
2121 return rc;
2122}
2123
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002124int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002125CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
Pavel Shilovskyba9ad7252012-09-18 16:20:30 -07002126 unsigned int *nbytes, struct kvec *iov, int n_vec)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002127{
2128 int rc = -EACCES;
2129 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08002130 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002131 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08002132 int resp_buf_type = 0;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002133 __u32 pid = io_parms->pid;
2134 __u16 netfid = io_parms->netfid;
2135 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00002136 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002137 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002138
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04002139 *nbytes = 0;
2140
Joe Perchesb6b38f72010-04-21 03:50:45 +00002141 cFYI(1, "write2 at %lld %d bytes", (long long)offset, count);
Steve Frenchff7feac2005-11-15 16:45:16 -08002142
Steve French4c3130e2008-12-09 00:28:16 +00002143 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07002144 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00002145 } else {
Steve French8cc64c62005-10-03 13:49:43 -07002146 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00002147 if ((offset >> 32) > 0) {
2148 /* can not handle big offset for old srv */
2149 return -EIO;
2150 }
2151 }
Steve French8cc64c62005-10-03 13:49:43 -07002152 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002153 if (rc)
2154 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002155
2156 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
2157 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
2158
Linus Torvalds1da177e2005-04-16 15:20:36 -07002159 /* tcon and ses pointer are checked in smb_init */
2160 if (tcon->ses->server == NULL)
2161 return -ECONNABORTED;
2162
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002163 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002164 pSMB->Fid = netfid;
2165 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00002166 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002167 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002168 pSMB->Reserved = 0xFFFFFFFF;
2169 pSMB->WriteMode = 0;
2170 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002171
Linus Torvalds1da177e2005-04-16 15:20:36 -07002172 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00002173 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002174
Steve French3e844692005-10-03 13:37:24 -07002175 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
2176 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002177 /* header + 1 byte pad */
2178 smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
Steve French790fe572007-07-07 19:25:05 +00002179 if (wct == 14)
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002180 inc_rfc1001_len(pSMB, count + 1);
Steve French8cc64c62005-10-03 13:49:43 -07002181 else /* wct == 12 */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002182 inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
Steve French790fe572007-07-07 19:25:05 +00002183 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002184 pSMB->ByteCount = cpu_to_le16(count + 1);
2185 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00002186 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07002187 (struct smb_com_writex_req *)pSMB;
2188 pSMBW->ByteCount = cpu_to_le16(count + 5);
2189 }
Steve French3e844692005-10-03 13:37:24 -07002190 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00002191 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08002192 iov[0].iov_len = smb_hdr_len + 4;
2193 else /* wct == 12 pad bigger by four bytes */
2194 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00002195
Steve French3e844692005-10-03 13:37:24 -07002196
Pavel Shilovskyba9ad7252012-09-18 16:20:30 -07002197 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002198 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002199 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002200 cFYI(1, "Send error Write2 = %d", rc);
Steve French790fe572007-07-07 19:25:05 +00002201 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08002202 /* presumably this can not happen, but best to be safe */
2203 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002204 } else {
Steve Frenchad7a2922008-02-07 23:25:02 +00002205 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002206 *nbytes = le16_to_cpu(pSMBr->CountHigh);
2207 *nbytes = (*nbytes) << 16;
2208 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05302209
2210 /*
2211 * Mask off high 16 bits when bytes written as returned by the
2212 * server is greater than bytes requested by the client. OS/2
2213 * servers are known to set incorrect CountHigh values.
2214 */
2215 if (*nbytes > count)
2216 *nbytes &= 0xFFFF;
Steve French50c2f752007-07-13 00:33:32 +00002217 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002218
Steve French4b8f9302006-02-26 16:41:18 +00002219/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00002220 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002221 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00002222 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002223 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002224
Steve French50c2f752007-07-13 00:33:32 +00002225 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002226 since file handle passed in no longer valid */
2227
2228 return rc;
2229}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002230
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002231int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon,
2232 const __u16 netfid, const __u8 lock_type, const __u32 num_unlock,
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002233 const __u32 num_lock, LOCKING_ANDX_RANGE *buf)
2234{
2235 int rc = 0;
2236 LOCK_REQ *pSMB = NULL;
2237 struct kvec iov[2];
2238 int resp_buf_type;
2239 __u16 count;
2240
2241 cFYI(1, "cifs_lockv num lock %d num unlock %d", num_lock, num_unlock);
2242
2243 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2244 if (rc)
2245 return rc;
2246
2247 pSMB->Timeout = 0;
2248 pSMB->NumberOfLocks = cpu_to_le16(num_lock);
2249 pSMB->NumberOfUnlocks = cpu_to_le16(num_unlock);
2250 pSMB->LockType = lock_type;
2251 pSMB->AndXCommand = 0xFF; /* none */
2252 pSMB->Fid = netfid; /* netfid stays le */
2253
2254 count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2255 inc_rfc1001_len(pSMB, count);
2256 pSMB->ByteCount = cpu_to_le16(count);
2257
2258 iov[0].iov_base = (char *)pSMB;
2259 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 -
2260 (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2261 iov[1].iov_base = (char *)buf;
2262 iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2263
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002264 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002265 rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP);
2266 if (rc)
2267 cFYI(1, "Send error in cifs_lockv = %d", rc);
2268
2269 return rc;
2270}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002271
Linus Torvalds1da177e2005-04-16 15:20:36 -07002272int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002273CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002274 const __u16 smb_file_id, const __u32 netpid, const __u64 len,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002275 const __u64 offset, const __u32 numUnlock,
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002276 const __u32 numLock, const __u8 lockType,
2277 const bool waitFlag, const __u8 oplock_level)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002278{
2279 int rc = 0;
2280 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002281/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002282 int bytes_returned;
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002283 int flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002284 __u16 count;
2285
Joe Perchesb6b38f72010-04-21 03:50:45 +00002286 cFYI(1, "CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock);
Steve French46810cb2005-04-28 22:41:09 -07002287 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2288
Linus Torvalds1da177e2005-04-16 15:20:36 -07002289 if (rc)
2290 return rc;
2291
Steve French790fe572007-07-07 19:25:05 +00002292 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002293 /* no response expected */
2294 flags = CIFS_ASYNC_OP | CIFS_OBREAK_OP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002295 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00002296 } else if (waitFlag) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002297 flags = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002298 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
2299 } else {
2300 pSMB->Timeout = 0;
2301 }
2302
2303 pSMB->NumberOfLocks = cpu_to_le16(numLock);
2304 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
2305 pSMB->LockType = lockType;
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002306 pSMB->OplockLevel = oplock_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002307 pSMB->AndXCommand = 0xFF; /* none */
2308 pSMB->Fid = smb_file_id; /* netfid stays le */
2309
Steve French790fe572007-07-07 19:25:05 +00002310 if ((numLock != 0) || (numUnlock != 0)) {
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002311 pSMB->Locks[0].Pid = cpu_to_le16(netpid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002312 /* BB where to store pid high? */
2313 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
2314 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
2315 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
2316 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
2317 count = sizeof(LOCKING_ANDX_RANGE);
2318 } else {
2319 /* oplock break */
2320 count = 0;
2321 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002322 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323 pSMB->ByteCount = cpu_to_le16(count);
2324
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002325 if (waitFlag) {
2326 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002327 (struct smb_hdr *) pSMB, &bytes_returned);
Steve French133672e2007-11-13 22:41:37 +00002328 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002329 } else {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002330 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, flags);
Steve French133672e2007-11-13 22:41:37 +00002331 /* SMB buffer freed by function above */
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002332 }
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002333 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002334 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002335 cFYI(1, "Send error in Lock = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002336
Steve French50c2f752007-07-13 00:33:32 +00002337 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002338 since file handle passed in no longer valid */
2339 return rc;
2340}
2341
2342int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002343CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002344 const __u16 smb_file_id, const __u32 netpid,
2345 const loff_t start_offset, const __u64 len,
2346 struct file_lock *pLockData, const __u16 lock_type,
2347 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00002348{
2349 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2350 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00002351 struct cifs_posix_lock *parm_data;
2352 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00002353 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00002354 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00002355 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00002356 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00002357 struct kvec iov[1];
Steve French08547b02006-02-28 22:39:25 +00002358
Joe Perchesb6b38f72010-04-21 03:50:45 +00002359 cFYI(1, "Posix Lock");
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002360
Steve French08547b02006-02-28 22:39:25 +00002361 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
2362
2363 if (rc)
2364 return rc;
2365
2366 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
2367
Steve French50c2f752007-07-13 00:33:32 +00002368 params = 6;
Steve French08547b02006-02-28 22:39:25 +00002369 pSMB->MaxSetupCount = 0;
2370 pSMB->Reserved = 0;
2371 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00002372 pSMB->Reserved2 = 0;
2373 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2374 offset = param_offset + params;
2375
Steve French08547b02006-02-28 22:39:25 +00002376 count = sizeof(struct cifs_posix_lock);
2377 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002378 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00002379 pSMB->SetupCount = 1;
2380 pSMB->Reserved3 = 0;
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002381 if (pLockData)
Steve French08547b02006-02-28 22:39:25 +00002382 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2383 else
2384 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2385 byte_count = 3 /* pad */ + params + count;
2386 pSMB->DataCount = cpu_to_le16(count);
2387 pSMB->ParameterCount = cpu_to_le16(params);
2388 pSMB->TotalDataCount = pSMB->DataCount;
2389 pSMB->TotalParameterCount = pSMB->ParameterCount;
2390 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00002391 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00002392 (((char *) &pSMB->hdr.Protocol) + offset);
2393
2394 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00002395 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00002396 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00002397 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00002398 pSMB->Timeout = cpu_to_le32(-1);
2399 } else
2400 pSMB->Timeout = 0;
2401
Pavel Shilovsky4f6bcec2011-10-22 15:33:30 +04002402 parm_data->pid = cpu_to_le32(netpid);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002403 parm_data->start = cpu_to_le64(start_offset);
Steve Frenchcec6815a2006-05-30 18:07:17 +00002404 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00002405
2406 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00002407 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00002408 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
2409 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002410 inc_rfc1001_len(pSMB, byte_count);
Steve French08547b02006-02-28 22:39:25 +00002411 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002412 if (waitFlag) {
2413 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2414 (struct smb_hdr *) pSMBr, &bytes_returned);
2415 } else {
Steve French133672e2007-11-13 22:41:37 +00002416 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002417 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French133672e2007-11-13 22:41:37 +00002418 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
2419 &resp_buf_type, timeout);
2420 pSMB = NULL; /* request buf already freed by SendReceive2. Do
2421 not try to free it twice below on exit */
2422 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002423 }
2424
Steve French08547b02006-02-28 22:39:25 +00002425 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002426 cFYI(1, "Send error in Posix Lock = %d", rc);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002427 } else if (pLockData) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002428 /* lock structure can be returned on get */
2429 __u16 data_offset;
2430 __u16 data_count;
2431 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00002432
Jeff Layton820a8032011-05-04 08:05:26 -04002433 if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002434 rc = -EIO; /* bad smb */
2435 goto plk_err_exit;
2436 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002437 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2438 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00002439 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002440 rc = -EIO;
2441 goto plk_err_exit;
2442 }
2443 parm_data = (struct cifs_posix_lock *)
2444 ((char *)&pSMBr->hdr.Protocol + data_offset);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002445 if (parm_data->lock_type == __constant_cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002446 pLockData->fl_type = F_UNLCK;
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002447 else {
2448 if (parm_data->lock_type ==
2449 __constant_cpu_to_le16(CIFS_RDLCK))
2450 pLockData->fl_type = F_RDLCK;
2451 else if (parm_data->lock_type ==
2452 __constant_cpu_to_le16(CIFS_WRLCK))
2453 pLockData->fl_type = F_WRLCK;
2454
Steve French5443d132011-03-13 05:08:25 +00002455 pLockData->fl_start = le64_to_cpu(parm_data->start);
2456 pLockData->fl_end = pLockData->fl_start +
2457 le64_to_cpu(parm_data->length) - 1;
2458 pLockData->fl_pid = le32_to_cpu(parm_data->pid);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002459 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002460 }
Steve French50c2f752007-07-13 00:33:32 +00002461
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002462plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00002463 if (pSMB)
2464 cifs_small_buf_release(pSMB);
2465
Steve French133672e2007-11-13 22:41:37 +00002466 if (resp_buf_type == CIFS_SMALL_BUFFER)
2467 cifs_small_buf_release(iov[0].iov_base);
2468 else if (resp_buf_type == CIFS_LARGE_BUFFER)
2469 cifs_buf_release(iov[0].iov_base);
2470
Steve French08547b02006-02-28 22:39:25 +00002471 /* Note: On -EAGAIN error only caller can retry on handle based calls
2472 since file handle passed in no longer valid */
2473
2474 return rc;
2475}
2476
2477
2478int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002479CIFSSMBClose(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002480{
2481 int rc = 0;
2482 CLOSE_REQ *pSMB = NULL;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002483 cFYI(1, "In CIFSSMBClose");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002484
2485/* do not retry on dead session on close */
2486 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00002487 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002488 return 0;
2489 if (rc)
2490 return rc;
2491
Linus Torvalds1da177e2005-04-16 15:20:36 -07002492 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00002493 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002494 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002495 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002496 cifs_stats_inc(&tcon->stats.cifs_stats.num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002497 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00002498 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002499 /* EINTR is expected when user ctl-c to kill app */
Joe Perchesb6b38f72010-04-21 03:50:45 +00002500 cERROR(1, "Send error in Close = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002501 }
2502 }
2503
Linus Torvalds1da177e2005-04-16 15:20:36 -07002504 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00002505 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002506 rc = 0;
2507
2508 return rc;
2509}
2510
2511int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002512CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Steve Frenchb298f222009-02-21 21:17:43 +00002513{
2514 int rc = 0;
2515 FLUSH_REQ *pSMB = NULL;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002516 cFYI(1, "In CIFSSMBFlush");
Steve Frenchb298f222009-02-21 21:17:43 +00002517
2518 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
2519 if (rc)
2520 return rc;
2521
2522 pSMB->FileID = (__u16) smb_file_id;
2523 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002524 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002525 cifs_stats_inc(&tcon->stats.cifs_stats.num_flushes);
Steve Frenchb298f222009-02-21 21:17:43 +00002526 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002527 cERROR(1, "Send error in Flush = %d", rc);
Steve Frenchb298f222009-02-21 21:17:43 +00002528
2529 return rc;
2530}
2531
2532int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002533CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002534 const char *from_name, const char *to_name,
2535 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002536{
2537 int rc = 0;
2538 RENAME_REQ *pSMB = NULL;
2539 RENAME_RSP *pSMBr = NULL;
2540 int bytes_returned;
2541 int name_len, name_len2;
2542 __u16 count;
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002543 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002544
Joe Perchesb6b38f72010-04-21 03:50:45 +00002545 cFYI(1, "In CIFSSMBRename");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002546renameRetry:
2547 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
2548 (void **) &pSMBr);
2549 if (rc)
2550 return rc;
2551
2552 pSMB->BufferFormat = 0x04;
2553 pSMB->SearchAttributes =
2554 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2555 ATTR_DIRECTORY);
2556
2557 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002558 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2559 from_name, PATH_MAX,
2560 cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002561 name_len++; /* trailing null */
2562 name_len *= 2;
2563 pSMB->OldFileName[name_len] = 0x04; /* pad */
2564 /* protocol requires ASCII signature byte on Unicode string */
2565 pSMB->OldFileName[name_len + 1] = 0x00;
2566 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002567 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002568 to_name, PATH_MAX, cifs_sb->local_nls,
2569 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002570 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2571 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002572 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002573 name_len = strnlen(from_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002574 name_len++; /* trailing null */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002575 strncpy(pSMB->OldFileName, from_name, name_len);
2576 name_len2 = strnlen(to_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002577 name_len2++; /* trailing null */
2578 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002579 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580 name_len2++; /* trailing null */
2581 name_len2++; /* signature byte */
2582 }
2583
2584 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002585 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002586 pSMB->ByteCount = cpu_to_le16(count);
2587
2588 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2589 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002590 cifs_stats_inc(&tcon->stats.cifs_stats.num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002591 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002592 cFYI(1, "Send error in rename = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002593
Linus Torvalds1da177e2005-04-16 15:20:36 -07002594 cifs_buf_release(pSMB);
2595
2596 if (rc == -EAGAIN)
2597 goto renameRetry;
2598
2599 return rc;
2600}
2601
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002602int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002603 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002604 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002605{
2606 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2607 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002608 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002609 char *data_offset;
2610 char dummy_string[30];
2611 int rc = 0;
2612 int bytes_returned = 0;
2613 int len_of_str;
2614 __u16 params, param_offset, offset, count, byte_count;
2615
Joe Perchesb6b38f72010-04-21 03:50:45 +00002616 cFYI(1, "Rename to File by handle");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002617 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2618 (void **) &pSMBr);
2619 if (rc)
2620 return rc;
2621
2622 params = 6;
2623 pSMB->MaxSetupCount = 0;
2624 pSMB->Reserved = 0;
2625 pSMB->Flags = 0;
2626 pSMB->Timeout = 0;
2627 pSMB->Reserved2 = 0;
2628 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2629 offset = param_offset + params;
2630
2631 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2632 rename_info = (struct set_file_rename *) data_offset;
2633 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002634 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635 pSMB->SetupCount = 1;
2636 pSMB->Reserved3 = 0;
2637 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2638 byte_count = 3 /* pad */ + params;
2639 pSMB->ParameterCount = cpu_to_le16(params);
2640 pSMB->TotalParameterCount = pSMB->ParameterCount;
2641 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2642 pSMB->DataOffset = cpu_to_le16(offset);
2643 /* construct random name ".cifs_tmp<inodenum><mid>" */
2644 rename_info->overwrite = cpu_to_le32(1);
2645 rename_info->root_fid = 0;
2646 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002647 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002648 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
Steve Frenchacbbb762012-01-18 22:32:33 -06002649 len_of_str =
2650 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002651 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002652 } else {
Steve Frenchacbbb762012-01-18 22:32:33 -06002653 len_of_str =
2654 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002655 target_name, PATH_MAX, nls_codepage,
2656 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657 }
2658 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002659 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660 byte_count += count;
2661 pSMB->DataCount = cpu_to_le16(count);
2662 pSMB->TotalDataCount = pSMB->DataCount;
2663 pSMB->Fid = netfid;
2664 pSMB->InformationLevel =
2665 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2666 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002667 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002668 pSMB->ByteCount = cpu_to_le16(byte_count);
2669 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002670 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002671 cifs_stats_inc(&pTcon->stats.cifs_stats.num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002672 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002673 cFYI(1, "Send error in Rename (by file handle) = %d", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07002674
Linus Torvalds1da177e2005-04-16 15:20:36 -07002675 cifs_buf_release(pSMB);
2676
2677 /* Note: On -EAGAIN error only caller can retry on handle based calls
2678 since file handle passed in no longer valid */
2679
2680 return rc;
2681}
2682
2683int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002684CIFSSMBCopy(const unsigned int xid, struct cifs_tcon *tcon,
2685 const char *fromName, const __u16 target_tid, const char *toName,
2686 const int flags, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002687{
2688 int rc = 0;
2689 COPY_REQ *pSMB = NULL;
2690 COPY_RSP *pSMBr = NULL;
2691 int bytes_returned;
2692 int name_len, name_len2;
2693 __u16 count;
2694
Joe Perchesb6b38f72010-04-21 03:50:45 +00002695 cFYI(1, "In CIFSSMBCopy");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002696copyRetry:
2697 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2698 (void **) &pSMBr);
2699 if (rc)
2700 return rc;
2701
2702 pSMB->BufferFormat = 0x04;
2703 pSMB->Tid2 = target_tid;
2704
2705 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2706
2707 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002708 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2709 fromName, PATH_MAX, nls_codepage,
2710 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002711 name_len++; /* trailing null */
2712 name_len *= 2;
2713 pSMB->OldFileName[name_len] = 0x04; /* pad */
2714 /* protocol requires ASCII signature byte on Unicode string */
2715 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002716 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002717 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2718 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002719 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2720 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002721 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002722 name_len = strnlen(fromName, PATH_MAX);
2723 name_len++; /* trailing null */
2724 strncpy(pSMB->OldFileName, fromName, name_len);
2725 name_len2 = strnlen(toName, PATH_MAX);
2726 name_len2++; /* trailing null */
2727 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2728 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2729 name_len2++; /* trailing null */
2730 name_len2++; /* signature byte */
2731 }
2732
2733 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002734 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735 pSMB->ByteCount = cpu_to_le16(count);
2736
2737 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2738 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2739 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002740 cFYI(1, "Send error in copy = %d with %d files copied",
2741 rc, le16_to_cpu(pSMBr->CopyCount));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002742 }
Steve French0d817bc2008-05-22 02:02:03 +00002743 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002744
2745 if (rc == -EAGAIN)
2746 goto copyRetry;
2747
2748 return rc;
2749}
2750
2751int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002752CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002753 const char *fromName, const char *toName,
2754 const struct nls_table *nls_codepage)
2755{
2756 TRANSACTION2_SPI_REQ *pSMB = NULL;
2757 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2758 char *data_offset;
2759 int name_len;
2760 int name_len_target;
2761 int rc = 0;
2762 int bytes_returned = 0;
2763 __u16 params, param_offset, offset, byte_count;
2764
Joe Perchesb6b38f72010-04-21 03:50:45 +00002765 cFYI(1, "In Symlink Unix style");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002766createSymLinkRetry:
2767 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2768 (void **) &pSMBr);
2769 if (rc)
2770 return rc;
2771
2772 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2773 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06002774 cifs_strtoUTF16((__le16 *) pSMB->FileName, fromName,
2775 /* find define for this maxpathcomponent */
2776 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002777 name_len++; /* trailing null */
2778 name_len *= 2;
2779
Steve French50c2f752007-07-13 00:33:32 +00002780 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002781 name_len = strnlen(fromName, PATH_MAX);
2782 name_len++; /* trailing null */
2783 strncpy(pSMB->FileName, fromName, name_len);
2784 }
2785 params = 6 + name_len;
2786 pSMB->MaxSetupCount = 0;
2787 pSMB->Reserved = 0;
2788 pSMB->Flags = 0;
2789 pSMB->Timeout = 0;
2790 pSMB->Reserved2 = 0;
2791 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002792 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002793 offset = param_offset + params;
2794
2795 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2796 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2797 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06002798 cifs_strtoUTF16((__le16 *) data_offset, toName, PATH_MAX
2799 /* find define for this maxpathcomponent */
2800 , nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002801 name_len_target++; /* trailing null */
2802 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002803 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002804 name_len_target = strnlen(toName, PATH_MAX);
2805 name_len_target++; /* trailing null */
2806 strncpy(data_offset, toName, name_len_target);
2807 }
2808
2809 pSMB->MaxParameterCount = cpu_to_le16(2);
2810 /* BB find exact max on data count below from sess */
2811 pSMB->MaxDataCount = cpu_to_le16(1000);
2812 pSMB->SetupCount = 1;
2813 pSMB->Reserved3 = 0;
2814 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2815 byte_count = 3 /* pad */ + params + name_len_target;
2816 pSMB->DataCount = cpu_to_le16(name_len_target);
2817 pSMB->ParameterCount = cpu_to_le16(params);
2818 pSMB->TotalDataCount = pSMB->DataCount;
2819 pSMB->TotalParameterCount = pSMB->ParameterCount;
2820 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2821 pSMB->DataOffset = cpu_to_le16(offset);
2822 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2823 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002824 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002825 pSMB->ByteCount = cpu_to_le16(byte_count);
2826 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2827 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002828 cifs_stats_inc(&tcon->stats.cifs_stats.num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002829 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002830 cFYI(1, "Send error in SetPathInfo create symlink = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002831
Steve French0d817bc2008-05-22 02:02:03 +00002832 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002833
2834 if (rc == -EAGAIN)
2835 goto createSymLinkRetry;
2836
2837 return rc;
2838}
2839
2840int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002841CIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002842 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002843 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002844{
2845 TRANSACTION2_SPI_REQ *pSMB = NULL;
2846 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2847 char *data_offset;
2848 int name_len;
2849 int name_len_target;
2850 int rc = 0;
2851 int bytes_returned = 0;
2852 __u16 params, param_offset, offset, byte_count;
2853
Joe Perchesb6b38f72010-04-21 03:50:45 +00002854 cFYI(1, "In Create Hard link Unix style");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002855createHardLinkRetry:
2856 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2857 (void **) &pSMBr);
2858 if (rc)
2859 return rc;
2860
2861 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002862 name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, toName,
2863 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002864 name_len++; /* trailing null */
2865 name_len *= 2;
2866
Steve French50c2f752007-07-13 00:33:32 +00002867 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002868 name_len = strnlen(toName, PATH_MAX);
2869 name_len++; /* trailing null */
2870 strncpy(pSMB->FileName, toName, name_len);
2871 }
2872 params = 6 + name_len;
2873 pSMB->MaxSetupCount = 0;
2874 pSMB->Reserved = 0;
2875 pSMB->Flags = 0;
2876 pSMB->Timeout = 0;
2877 pSMB->Reserved2 = 0;
2878 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002879 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002880 offset = param_offset + params;
2881
2882 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2883 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2884 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06002885 cifsConvertToUTF16((__le16 *) data_offset, fromName,
2886 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002887 name_len_target++; /* trailing null */
2888 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002889 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002890 name_len_target = strnlen(fromName, PATH_MAX);
2891 name_len_target++; /* trailing null */
2892 strncpy(data_offset, fromName, name_len_target);
2893 }
2894
2895 pSMB->MaxParameterCount = cpu_to_le16(2);
2896 /* BB find exact max on data count below from sess*/
2897 pSMB->MaxDataCount = cpu_to_le16(1000);
2898 pSMB->SetupCount = 1;
2899 pSMB->Reserved3 = 0;
2900 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2901 byte_count = 3 /* pad */ + params + name_len_target;
2902 pSMB->ParameterCount = cpu_to_le16(params);
2903 pSMB->TotalParameterCount = pSMB->ParameterCount;
2904 pSMB->DataCount = cpu_to_le16(name_len_target);
2905 pSMB->TotalDataCount = pSMB->DataCount;
2906 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2907 pSMB->DataOffset = cpu_to_le16(offset);
2908 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2909 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002910 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002911 pSMB->ByteCount = cpu_to_le16(byte_count);
2912 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2913 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002914 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002915 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002916 cFYI(1, "Send error in SetPathInfo (hard link) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002917
2918 cifs_buf_release(pSMB);
2919 if (rc == -EAGAIN)
2920 goto createHardLinkRetry;
2921
2922 return rc;
2923}
2924
2925int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002926CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002927 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002928 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002929{
2930 int rc = 0;
2931 NT_RENAME_REQ *pSMB = NULL;
2932 RENAME_RSP *pSMBr = NULL;
2933 int bytes_returned;
2934 int name_len, name_len2;
2935 __u16 count;
2936
Joe Perchesb6b38f72010-04-21 03:50:45 +00002937 cFYI(1, "In CIFSCreateHardLink");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002938winCreateHardLinkRetry:
2939
2940 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2941 (void **) &pSMBr);
2942 if (rc)
2943 return rc;
2944
2945 pSMB->SearchAttributes =
2946 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2947 ATTR_DIRECTORY);
2948 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2949 pSMB->ClusterCount = 0;
2950
2951 pSMB->BufferFormat = 0x04;
2952
2953 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2954 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06002955 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, fromName,
2956 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002957 name_len++; /* trailing null */
2958 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05002959
2960 /* protocol specifies ASCII buffer format (0x04) for unicode */
2961 pSMB->OldFileName[name_len] = 0x04;
2962 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002963 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002964 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2965 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002966 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2967 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002968 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002969 name_len = strnlen(fromName, PATH_MAX);
2970 name_len++; /* trailing null */
2971 strncpy(pSMB->OldFileName, fromName, name_len);
2972 name_len2 = strnlen(toName, PATH_MAX);
2973 name_len2++; /* trailing null */
2974 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2975 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2976 name_len2++; /* trailing null */
2977 name_len2++; /* signature byte */
2978 }
2979
2980 count = 1 /* string type byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002981 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002982 pSMB->ByteCount = cpu_to_le16(count);
2983
2984 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2985 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002986 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002987 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002988 cFYI(1, "Send error in hard link (NT rename) = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00002989
Linus Torvalds1da177e2005-04-16 15:20:36 -07002990 cifs_buf_release(pSMB);
2991 if (rc == -EAGAIN)
2992 goto winCreateHardLinkRetry;
2993
2994 return rc;
2995}
2996
2997int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002998CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04002999 const unsigned char *searchName, char **symlinkinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003000 const struct nls_table *nls_codepage)
3001{
3002/* SMB_QUERY_FILE_UNIX_LINK */
3003 TRANSACTION2_QPI_REQ *pSMB = NULL;
3004 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3005 int rc = 0;
3006 int bytes_returned;
3007 int name_len;
3008 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04003009 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003010
Joe Perchesb6b38f72010-04-21 03:50:45 +00003011 cFYI(1, "In QPathSymLinkInfo (Unix) for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003012
3013querySymLinkRetry:
3014 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3015 (void **) &pSMBr);
3016 if (rc)
3017 return rc;
3018
3019 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3020 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003021 cifs_strtoUTF16((__le16 *) pSMB->FileName, searchName,
3022 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003023 name_len++; /* trailing null */
3024 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003025 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003026 name_len = strnlen(searchName, PATH_MAX);
3027 name_len++; /* trailing null */
3028 strncpy(pSMB->FileName, searchName, name_len);
3029 }
3030
3031 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3032 pSMB->TotalDataCount = 0;
3033 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04003034 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003035 pSMB->MaxSetupCount = 0;
3036 pSMB->Reserved = 0;
3037 pSMB->Flags = 0;
3038 pSMB->Timeout = 0;
3039 pSMB->Reserved2 = 0;
3040 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003041 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003042 pSMB->DataCount = 0;
3043 pSMB->DataOffset = 0;
3044 pSMB->SetupCount = 1;
3045 pSMB->Reserved3 = 0;
3046 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3047 byte_count = params + 1 /* pad */ ;
3048 pSMB->TotalParameterCount = cpu_to_le16(params);
3049 pSMB->ParameterCount = pSMB->TotalParameterCount;
3050 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
3051 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003052 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003053 pSMB->ByteCount = cpu_to_le16(byte_count);
3054
3055 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3056 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3057 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003058 cFYI(1, "Send error in QuerySymLinkInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003059 } else {
3060 /* decode response */
3061
3062 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003063 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003064 if (rc || get_bcc(&pSMBr->hdr) < 2)
Jeff Layton460b9692009-04-30 07:17:56 -04003065 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003066 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00003067 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04003068 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003069
Jeff Layton460b9692009-04-30 07:17:56 -04003070 data_start = ((char *) &pSMBr->hdr.Protocol) +
3071 le16_to_cpu(pSMBr->t2.DataOffset);
3072
Steve French0e0d2cf2009-05-01 05:27:32 +00003073 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3074 is_unicode = true;
3075 else
3076 is_unicode = false;
3077
Steve French737b7582005-04-28 22:41:06 -07003078 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchacbbb762012-01-18 22:32:33 -06003079 *symlinkinfo = cifs_strndup_from_utf16(data_start,
3080 count, is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04003081 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04003082 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003083 }
3084 }
3085 cifs_buf_release(pSMB);
3086 if (rc == -EAGAIN)
3087 goto querySymLinkRetry;
3088 return rc;
3089}
3090
Steve Frenchc52a9552011-02-24 06:16:22 +00003091#ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL
3092/*
3093 * Recent Windows versions now create symlinks more frequently
3094 * and they use the "reparse point" mechanism below. We can of course
3095 * do symlinks nicely to Samba and other servers which support the
3096 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
3097 * "MF" symlinks optionally, but for recent Windows we really need to
3098 * reenable the code below and fix the cifs_symlink callers to handle this.
3099 * In the interim this code has been moved to its own config option so
3100 * it is not compiled in by default until callers fixed up and more tested.
3101 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003102int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003103CIFSSMBQueryReparseLinkInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003104 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00003105 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003106 const struct nls_table *nls_codepage)
3107{
3108 int rc = 0;
3109 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00003110 struct smb_com_transaction_ioctl_req *pSMB;
3111 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003112
Joe Perchesb6b38f72010-04-21 03:50:45 +00003113 cFYI(1, "In Windows reparse style QueryLink for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003114 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3115 (void **) &pSMBr);
3116 if (rc)
3117 return rc;
3118
3119 pSMB->TotalParameterCount = 0 ;
3120 pSMB->TotalDataCount = 0;
3121 pSMB->MaxParameterCount = cpu_to_le32(2);
3122 /* BB find exact data count max from sess structure BB */
Jeff Laytonc974bef2011-10-11 06:41:32 -04003123 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003124 pSMB->MaxSetupCount = 4;
3125 pSMB->Reserved = 0;
3126 pSMB->ParameterOffset = 0;
3127 pSMB->DataCount = 0;
3128 pSMB->DataOffset = 0;
3129 pSMB->SetupCount = 4;
3130 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
3131 pSMB->ParameterCount = pSMB->TotalParameterCount;
3132 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
3133 pSMB->IsFsctl = 1; /* FSCTL */
3134 pSMB->IsRootFlag = 0;
3135 pSMB->Fid = fid; /* file handle always le */
3136 pSMB->ByteCount = 0;
3137
3138 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3139 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3140 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003141 cFYI(1, "Send error in QueryReparseLinkInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003142 } else { /* decode response */
3143 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
3144 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
Jeff Layton820a8032011-05-04 08:05:26 -04003145 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
3146 /* BB also check enough total bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003147 rc = -EIO; /* bad smb */
Steve Frenchafe48c32009-05-02 05:25:46 +00003148 goto qreparse_out;
3149 }
3150 if (data_count && (data_count < 2048)) {
3151 char *end_of_smb = 2 /* sizeof byte count */ +
Jeff Layton820a8032011-05-04 08:05:26 -04003152 get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003153
Steve Frenchafe48c32009-05-02 05:25:46 +00003154 struct reparse_data *reparse_buf =
Steve French50c2f752007-07-13 00:33:32 +00003155 (struct reparse_data *)
3156 ((char *)&pSMBr->hdr.Protocol
3157 + data_offset);
Steve Frenchafe48c32009-05-02 05:25:46 +00003158 if ((char *)reparse_buf >= end_of_smb) {
3159 rc = -EIO;
3160 goto qreparse_out;
3161 }
3162 if ((reparse_buf->LinkNamesBuf +
3163 reparse_buf->TargetNameOffset +
3164 reparse_buf->TargetNameLen) > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003165 cFYI(1, "reparse buf beyond SMB");
Steve Frenchafe48c32009-05-02 05:25:46 +00003166 rc = -EIO;
3167 goto qreparse_out;
3168 }
Steve French50c2f752007-07-13 00:33:32 +00003169
Steve Frenchafe48c32009-05-02 05:25:46 +00003170 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3171 cifs_from_ucs2(symlinkinfo, (__le16 *)
Steve French50c2f752007-07-13 00:33:32 +00003172 (reparse_buf->LinkNamesBuf +
3173 reparse_buf->TargetNameOffset),
Steve Frenchafe48c32009-05-02 05:25:46 +00003174 buflen,
3175 reparse_buf->TargetNameLen,
3176 nls_codepage, 0);
3177 } else { /* ASCII names */
3178 strncpy(symlinkinfo,
3179 reparse_buf->LinkNamesBuf +
3180 reparse_buf->TargetNameOffset,
3181 min_t(const int, buflen,
3182 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003183 }
Steve Frenchafe48c32009-05-02 05:25:46 +00003184 } else {
3185 rc = -EIO;
Joe Perchesb6b38f72010-04-21 03:50:45 +00003186 cFYI(1, "Invalid return data count on "
3187 "get reparse info ioctl");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003188 }
Steve Frenchafe48c32009-05-02 05:25:46 +00003189 symlinkinfo[buflen] = 0; /* just in case so the caller
3190 does not go off the end of the buffer */
Joe Perchesb6b38f72010-04-21 03:50:45 +00003191 cFYI(1, "readlink result - %s", symlinkinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003192 }
Steve French989c7e52009-05-02 05:32:20 +00003193
Linus Torvalds1da177e2005-04-16 15:20:36 -07003194qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07003195 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003196
3197 /* Note: On -EAGAIN error only caller can retry on handle based calls
3198 since file handle passed in no longer valid */
3199
3200 return rc;
3201}
Steve Frenchc52a9552011-02-24 06:16:22 +00003202#endif /* CIFS_SYMLINK_EXPERIMENTAL */ /* BB temporarily unused */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003203
3204#ifdef CONFIG_CIFS_POSIX
3205
3206/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00003207static void cifs_convert_ace(posix_acl_xattr_entry *ace,
3208 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003209{
3210 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08003211 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
3212 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
3213 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesb6b38f72010-04-21 03:50:45 +00003214 /* cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003215
3216 return;
3217}
3218
3219/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00003220static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
3221 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003222{
3223 int size = 0;
3224 int i;
3225 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00003226 struct cifs_posix_ace *pACE;
3227 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
3228 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003229
3230 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
3231 return -EOPNOTSUPP;
3232
Steve French790fe572007-07-07 19:25:05 +00003233 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003234 count = le16_to_cpu(cifs_acl->access_entry_count);
3235 pACE = &cifs_acl->ace_array[0];
3236 size = sizeof(struct cifs_posix_acl);
3237 size += sizeof(struct cifs_posix_ace) * count;
3238 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003239 if (size_of_data_area < size) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003240 cFYI(1, "bad CIFS POSIX ACL size %d vs. %d",
3241 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003242 return -EINVAL;
3243 }
Steve French790fe572007-07-07 19:25:05 +00003244 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003245 count = le16_to_cpu(cifs_acl->access_entry_count);
3246 size = sizeof(struct cifs_posix_acl);
3247 size += sizeof(struct cifs_posix_ace) * count;
3248/* skip past access ACEs to get to default ACEs */
3249 pACE = &cifs_acl->ace_array[count];
3250 count = le16_to_cpu(cifs_acl->default_entry_count);
3251 size += sizeof(struct cifs_posix_ace) * count;
3252 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003253 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003254 return -EINVAL;
3255 } else {
3256 /* illegal type */
3257 return -EINVAL;
3258 }
3259
3260 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00003261 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00003262 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00003263 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003264 return -ERANGE;
3265 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08003266 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00003267 for (i = 0; i < count ; i++) {
3268 cifs_convert_ace(&local_acl->a_entries[i], pACE);
3269 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003270 }
3271 }
3272 return size;
3273}
3274
Steve French50c2f752007-07-13 00:33:32 +00003275static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
3276 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003277{
3278 __u16 rc = 0; /* 0 = ACL converted ok */
3279
Steve Frenchff7feac2005-11-15 16:45:16 -08003280 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
3281 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003282 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00003283 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003284 /* Probably no need to le convert -1 on any arch but can not hurt */
3285 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00003286 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08003287 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesb6b38f72010-04-21 03:50:45 +00003288 /*cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id);*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003289 return rc;
3290}
3291
3292/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00003293static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
3294 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003295{
3296 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00003297 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
3298 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003299 int count;
3300 int i;
3301
Steve French790fe572007-07-07 19:25:05 +00003302 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003303 return 0;
3304
3305 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesb6b38f72010-04-21 03:50:45 +00003306 cFYI(1, "setting acl with %d entries from buf of length %d and "
Steve French63135e02007-07-17 17:34:02 +00003307 "version of %d",
Joe Perchesb6b38f72010-04-21 03:50:45 +00003308 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00003309 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003310 cFYI(1, "unknown POSIX ACL version %d",
3311 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003312 return 0;
3313 }
3314 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00003315 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08003316 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00003317 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08003318 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003319 else {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003320 cFYI(1, "unknown ACL type %d", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003321 return 0;
3322 }
Steve French50c2f752007-07-13 00:33:32 +00003323 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003324 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
3325 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00003326 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003327 /* ACE not converted */
3328 break;
3329 }
3330 }
Steve French790fe572007-07-07 19:25:05 +00003331 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003332 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
3333 rc += sizeof(struct cifs_posix_acl);
3334 /* BB add check to make sure ACL does not overflow SMB */
3335 }
3336 return rc;
3337}
3338
3339int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003340CIFSSMBGetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003341 const unsigned char *searchName,
3342 char *acl_inf, const int buflen, const int acl_type,
3343 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003344{
3345/* SMB_QUERY_POSIX_ACL */
3346 TRANSACTION2_QPI_REQ *pSMB = NULL;
3347 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3348 int rc = 0;
3349 int bytes_returned;
3350 int name_len;
3351 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00003352
Joe Perchesb6b38f72010-04-21 03:50:45 +00003353 cFYI(1, "In GetPosixACL (Unix) for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003354
3355queryAclRetry:
3356 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3357 (void **) &pSMBr);
3358 if (rc)
3359 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003360
Linus Torvalds1da177e2005-04-16 15:20:36 -07003361 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3362 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003363 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3364 searchName, PATH_MAX, nls_codepage,
3365 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003366 name_len++; /* trailing null */
3367 name_len *= 2;
3368 pSMB->FileName[name_len] = 0;
3369 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00003370 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003371 name_len = strnlen(searchName, PATH_MAX);
3372 name_len++; /* trailing null */
3373 strncpy(pSMB->FileName, searchName, name_len);
3374 }
3375
3376 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3377 pSMB->TotalDataCount = 0;
3378 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00003379 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003380 pSMB->MaxDataCount = cpu_to_le16(4000);
3381 pSMB->MaxSetupCount = 0;
3382 pSMB->Reserved = 0;
3383 pSMB->Flags = 0;
3384 pSMB->Timeout = 0;
3385 pSMB->Reserved2 = 0;
3386 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003387 offsetof(struct smb_com_transaction2_qpi_req,
3388 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003389 pSMB->DataCount = 0;
3390 pSMB->DataOffset = 0;
3391 pSMB->SetupCount = 1;
3392 pSMB->Reserved3 = 0;
3393 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3394 byte_count = params + 1 /* pad */ ;
3395 pSMB->TotalParameterCount = cpu_to_le16(params);
3396 pSMB->ParameterCount = pSMB->TotalParameterCount;
3397 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
3398 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003399 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003400 pSMB->ByteCount = cpu_to_le16(byte_count);
3401
3402 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3403 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003404 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003405 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003406 cFYI(1, "Send error in Query POSIX ACL = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003407 } else {
3408 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00003409
Linus Torvalds1da177e2005-04-16 15:20:36 -07003410 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003411 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003412 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003413 rc = -EIO; /* bad smb */
3414 else {
3415 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3416 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3417 rc = cifs_copy_posix_acl(acl_inf,
3418 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00003419 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003420 }
3421 }
3422 cifs_buf_release(pSMB);
3423 if (rc == -EAGAIN)
3424 goto queryAclRetry;
3425 return rc;
3426}
3427
3428int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003429CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003430 const unsigned char *fileName,
3431 const char *local_acl, const int buflen,
3432 const int acl_type,
3433 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003434{
3435 struct smb_com_transaction2_spi_req *pSMB = NULL;
3436 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3437 char *parm_data;
3438 int name_len;
3439 int rc = 0;
3440 int bytes_returned = 0;
3441 __u16 params, byte_count, data_count, param_offset, offset;
3442
Joe Perchesb6b38f72010-04-21 03:50:45 +00003443 cFYI(1, "In SetPosixACL (Unix) for path %s", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003444setAclRetry:
3445 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003446 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003447 if (rc)
3448 return rc;
3449 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3450 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003451 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
3452 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003453 name_len++; /* trailing null */
3454 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003455 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003456 name_len = strnlen(fileName, PATH_MAX);
3457 name_len++; /* trailing null */
3458 strncpy(pSMB->FileName, fileName, name_len);
3459 }
3460 params = 6 + name_len;
3461 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003462 /* BB find max SMB size from sess */
3463 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003464 pSMB->MaxSetupCount = 0;
3465 pSMB->Reserved = 0;
3466 pSMB->Flags = 0;
3467 pSMB->Timeout = 0;
3468 pSMB->Reserved2 = 0;
3469 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003470 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003471 offset = param_offset + params;
3472 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
3473 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3474
3475 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00003476 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003477
Steve French790fe572007-07-07 19:25:05 +00003478 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003479 rc = -EOPNOTSUPP;
3480 goto setACLerrorExit;
3481 }
3482 pSMB->DataOffset = cpu_to_le16(offset);
3483 pSMB->SetupCount = 1;
3484 pSMB->Reserved3 = 0;
3485 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3486 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
3487 byte_count = 3 /* pad */ + params + data_count;
3488 pSMB->DataCount = cpu_to_le16(data_count);
3489 pSMB->TotalDataCount = pSMB->DataCount;
3490 pSMB->ParameterCount = cpu_to_le16(params);
3491 pSMB->TotalParameterCount = pSMB->ParameterCount;
3492 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003493 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003494 pSMB->ByteCount = cpu_to_le16(byte_count);
3495 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003496 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003497 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003498 cFYI(1, "Set POSIX ACL returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003499
3500setACLerrorExit:
3501 cifs_buf_release(pSMB);
3502 if (rc == -EAGAIN)
3503 goto setAclRetry;
3504 return rc;
3505}
3506
Steve Frenchf654bac2005-04-28 22:41:04 -07003507/* BB fix tabs in this function FIXME BB */
3508int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003509CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00003510 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07003511{
Steve French50c2f752007-07-13 00:33:32 +00003512 int rc = 0;
3513 struct smb_t2_qfi_req *pSMB = NULL;
3514 struct smb_t2_qfi_rsp *pSMBr = NULL;
3515 int bytes_returned;
3516 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07003517
Joe Perchesb6b38f72010-04-21 03:50:45 +00003518 cFYI(1, "In GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00003519 if (tcon == NULL)
3520 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07003521
3522GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003523 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3524 (void **) &pSMBr);
3525 if (rc)
3526 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003527
Steve Frenchad7a2922008-02-07 23:25:02 +00003528 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003529 pSMB->t2.TotalDataCount = 0;
3530 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3531 /* BB find exact max data count below from sess structure BB */
3532 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3533 pSMB->t2.MaxSetupCount = 0;
3534 pSMB->t2.Reserved = 0;
3535 pSMB->t2.Flags = 0;
3536 pSMB->t2.Timeout = 0;
3537 pSMB->t2.Reserved2 = 0;
3538 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3539 Fid) - 4);
3540 pSMB->t2.DataCount = 0;
3541 pSMB->t2.DataOffset = 0;
3542 pSMB->t2.SetupCount = 1;
3543 pSMB->t2.Reserved3 = 0;
3544 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3545 byte_count = params + 1 /* pad */ ;
3546 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3547 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3548 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3549 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003550 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003551 inc_rfc1001_len(pSMB, byte_count);
Steve French790fe572007-07-07 19:25:05 +00003552 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003553
Steve French790fe572007-07-07 19:25:05 +00003554 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3555 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3556 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003557 cFYI(1, "error %d in GetExtAttr", rc);
Steve French790fe572007-07-07 19:25:05 +00003558 } else {
3559 /* decode response */
3560 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003561 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003562 if (rc || get_bcc(&pSMBr->hdr) < 2)
Steve French790fe572007-07-07 19:25:05 +00003563 /* If rc should we check for EOPNOSUPP and
3564 disable the srvino flag? or in caller? */
3565 rc = -EIO; /* bad smb */
3566 else {
3567 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3568 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3569 struct file_chattr_info *pfinfo;
3570 /* BB Do we need a cast or hash here ? */
3571 if (count != 16) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003572 cFYI(1, "Illegal size ret in GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00003573 rc = -EIO;
3574 goto GetExtAttrOut;
3575 }
3576 pfinfo = (struct file_chattr_info *)
3577 (data_offset + (char *) &pSMBr->hdr.Protocol);
3578 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003579 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003580 }
3581 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003582GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003583 cifs_buf_release(pSMB);
3584 if (rc == -EAGAIN)
3585 goto GetExtAttrRetry;
3586 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003587}
3588
Steve Frenchf654bac2005-04-28 22:41:04 -07003589#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003590
Jeff Layton79df1ba2010-12-06 12:52:08 -05003591#ifdef CONFIG_CIFS_ACL
3592/*
3593 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3594 * all NT TRANSACTS that we init here have total parm and data under about 400
3595 * bytes (to fit in small cifs buffer size), which is the case so far, it
3596 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3597 * returned setup area) and MaxParameterCount (returned parms size) must be set
3598 * by caller
3599 */
3600static int
3601smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French96daf2b2011-05-27 04:34:02 +00003602 const int parm_len, struct cifs_tcon *tcon,
Jeff Layton79df1ba2010-12-06 12:52:08 -05003603 void **ret_buf)
3604{
3605 int rc;
3606 __u32 temp_offset;
3607 struct smb_com_ntransact_req *pSMB;
3608
3609 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3610 (void **)&pSMB);
3611 if (rc)
3612 return rc;
3613 *ret_buf = (void *)pSMB;
3614 pSMB->Reserved = 0;
3615 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3616 pSMB->TotalDataCount = 0;
Jeff Laytonc974bef2011-10-11 06:41:32 -04003617 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003618 pSMB->ParameterCount = pSMB->TotalParameterCount;
3619 pSMB->DataCount = pSMB->TotalDataCount;
3620 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3621 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3622 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3623 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3624 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3625 pSMB->SubCommand = cpu_to_le16(sub_command);
3626 return 0;
3627}
3628
3629static int
3630validate_ntransact(char *buf, char **ppparm, char **ppdata,
3631 __u32 *pparmlen, __u32 *pdatalen)
3632{
3633 char *end_of_smb;
3634 __u32 data_count, data_offset, parm_count, parm_offset;
3635 struct smb_com_ntransact_rsp *pSMBr;
Jeff Layton820a8032011-05-04 08:05:26 -04003636 u16 bcc;
Jeff Layton79df1ba2010-12-06 12:52:08 -05003637
3638 *pdatalen = 0;
3639 *pparmlen = 0;
3640
3641 if (buf == NULL)
3642 return -EINVAL;
3643
3644 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3645
Jeff Layton820a8032011-05-04 08:05:26 -04003646 bcc = get_bcc(&pSMBr->hdr);
3647 end_of_smb = 2 /* sizeof byte count */ + bcc +
Jeff Layton79df1ba2010-12-06 12:52:08 -05003648 (char *)&pSMBr->ByteCount;
3649
3650 data_offset = le32_to_cpu(pSMBr->DataOffset);
3651 data_count = le32_to_cpu(pSMBr->DataCount);
3652 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3653 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3654
3655 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3656 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3657
3658 /* should we also check that parm and data areas do not overlap? */
3659 if (*ppparm > end_of_smb) {
3660 cFYI(1, "parms start after end of smb");
3661 return -EINVAL;
3662 } else if (parm_count + *ppparm > end_of_smb) {
3663 cFYI(1, "parm end after end of smb");
3664 return -EINVAL;
3665 } else if (*ppdata > end_of_smb) {
3666 cFYI(1, "data starts after end of smb");
3667 return -EINVAL;
3668 } else if (data_count + *ppdata > end_of_smb) {
3669 cFYI(1, "data %p + count %d (%p) past smb end %p start %p",
3670 *ppdata, data_count, (data_count + *ppdata),
3671 end_of_smb, pSMBr);
3672 return -EINVAL;
Jeff Layton820a8032011-05-04 08:05:26 -04003673 } else if (parm_count + data_count > bcc) {
Jeff Layton79df1ba2010-12-06 12:52:08 -05003674 cFYI(1, "parm count and data count larger than SMB");
3675 return -EINVAL;
3676 }
3677 *pdatalen = data_count;
3678 *pparmlen = parm_count;
3679 return 0;
3680}
3681
Steve French0a4b92c2006-01-12 15:44:21 -08003682/* Get Security Descriptor (by handle) from remote server for a file or dir */
3683int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003684CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003685 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003686{
3687 int rc = 0;
3688 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003689 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003690 struct kvec iov[1];
3691
Joe Perchesb6b38f72010-04-21 03:50:45 +00003692 cFYI(1, "GetCifsACL");
Steve French0a4b92c2006-01-12 15:44:21 -08003693
Steve French630f3f0c2007-10-25 21:17:17 +00003694 *pbuflen = 0;
3695 *acl_inf = NULL;
3696
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003697 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003698 8 /* parm len */, tcon, (void **) &pSMB);
3699 if (rc)
3700 return rc;
3701
3702 pSMB->MaxParameterCount = cpu_to_le32(4);
3703 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3704 pSMB->MaxSetupCount = 0;
3705 pSMB->Fid = fid; /* file handle always le */
3706 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3707 CIFS_ACL_DACL);
3708 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003709 inc_rfc1001_len(pSMB, 11);
Steve French0a4b92c2006-01-12 15:44:21 -08003710 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003711 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French0a4b92c2006-01-12 15:44:21 -08003712
Steve Frencha761ac52007-10-18 21:45:27 +00003713 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Jeff Layton77499812011-01-11 07:24:23 -05003714 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003715 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Steve French0a4b92c2006-01-12 15:44:21 -08003716 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003717 cFYI(1, "Send error in QuerySecDesc = %d", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08003718 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003719 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003720 __u32 parm_len;
3721 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003722 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003723 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003724
3725/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003726 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003727 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003728 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003729 goto qsec_out;
3730 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3731
Joe Perchesb6b38f72010-04-21 03:50:45 +00003732 cFYI(1, "smb %p parm %p data %p", pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08003733
3734 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3735 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003736 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003737 goto qsec_out;
3738 }
3739
3740/* BB check that data area is minimum length and as big as acl_len */
3741
Steve Frenchaf6f4612007-10-16 18:40:37 +00003742 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003743 if (acl_len != *pbuflen) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003744 cERROR(1, "acl length %d does not match %d",
3745 acl_len, *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003746 if (*pbuflen > acl_len)
3747 *pbuflen = acl_len;
3748 }
Steve French0a4b92c2006-01-12 15:44:21 -08003749
Steve French630f3f0c2007-10-25 21:17:17 +00003750 /* check if buffer is big enough for the acl
3751 header followed by the smallest SID */
3752 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3753 (*pbuflen >= 64 * 1024)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003754 cERROR(1, "bad acl length %d", *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003755 rc = -EINVAL;
3756 *pbuflen = 0;
3757 } else {
3758 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3759 if (*acl_inf == NULL) {
3760 *pbuflen = 0;
3761 rc = -ENOMEM;
3762 }
3763 memcpy(*acl_inf, pdata, *pbuflen);
3764 }
Steve French0a4b92c2006-01-12 15:44:21 -08003765 }
3766qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003767 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003768 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003769 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003770 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003771/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003772 return rc;
3773}
Steve French97837582007-12-31 07:47:21 +00003774
3775int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003776CIFSSMBSetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003777 struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
Steve French97837582007-12-31 07:47:21 +00003778{
3779 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3780 int rc = 0;
3781 int bytes_returned = 0;
3782 SET_SEC_DESC_REQ *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003783 void *pSMBr;
Steve French97837582007-12-31 07:47:21 +00003784
3785setCifsAclRetry:
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003786 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, &pSMBr);
Steve French97837582007-12-31 07:47:21 +00003787 if (rc)
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003788 return rc;
Steve French97837582007-12-31 07:47:21 +00003789
3790 pSMB->MaxSetupCount = 0;
3791 pSMB->Reserved = 0;
3792
3793 param_count = 8;
3794 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3795 data_count = acllen;
3796 data_offset = param_offset + param_count;
3797 byte_count = 3 /* pad */ + param_count;
3798
3799 pSMB->DataCount = cpu_to_le32(data_count);
3800 pSMB->TotalDataCount = pSMB->DataCount;
3801 pSMB->MaxParameterCount = cpu_to_le32(4);
3802 pSMB->MaxDataCount = cpu_to_le32(16384);
3803 pSMB->ParameterCount = cpu_to_le32(param_count);
3804 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3805 pSMB->TotalParameterCount = pSMB->ParameterCount;
3806 pSMB->DataOffset = cpu_to_le32(data_offset);
3807 pSMB->SetupCount = 0;
3808 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3809 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3810
3811 pSMB->Fid = fid; /* file handle always le */
3812 pSMB->Reserved2 = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003813 pSMB->AclFlags = cpu_to_le32(aclflag);
Steve French97837582007-12-31 07:47:21 +00003814
3815 if (pntsd && acllen) {
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003816 memcpy((char *)pSMBr + offsetof(struct smb_hdr, Protocol) +
3817 data_offset, pntsd, acllen);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003818 inc_rfc1001_len(pSMB, byte_count + data_count);
Steve French97837582007-12-31 07:47:21 +00003819 } else
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003820 inc_rfc1001_len(pSMB, byte_count);
Steve French97837582007-12-31 07:47:21 +00003821
3822 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3823 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3824
Joe Perchesb6b38f72010-04-21 03:50:45 +00003825 cFYI(1, "SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00003826 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003827 cFYI(1, "Set CIFS ACL returned %d", rc);
Steve French97837582007-12-31 07:47:21 +00003828 cifs_buf_release(pSMB);
3829
3830 if (rc == -EAGAIN)
3831 goto setCifsAclRetry;
3832
3833 return (rc);
3834}
3835
Jeff Layton79df1ba2010-12-06 12:52:08 -05003836#endif /* CONFIG_CIFS_ACL */
Steve French0a4b92c2006-01-12 15:44:21 -08003837
Steve French6b8edfe2005-08-23 20:26:03 -07003838/* Legacy Query Path Information call for lookup to old servers such
3839 as Win9x/WinME */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003840int
3841SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon,
3842 const char *search_name, FILE_ALL_INFO *data,
3843 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003844{
Steve Frenchad7a2922008-02-07 23:25:02 +00003845 QUERY_INFORMATION_REQ *pSMB;
3846 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003847 int rc = 0;
3848 int bytes_returned;
3849 int name_len;
3850
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003851 cFYI(1, "In SMBQPath path %s", search_name);
Steve French6b8edfe2005-08-23 20:26:03 -07003852QInfRetry:
3853 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003854 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003855 if (rc)
3856 return rc;
3857
3858 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3859 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003860 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003861 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06003862 remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003863 name_len++; /* trailing null */
3864 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003865 } else {
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003866 name_len = strnlen(search_name, PATH_MAX);
Steve French6b8edfe2005-08-23 20:26:03 -07003867 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003868 strncpy(pSMB->FileName, search_name, name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07003869 }
3870 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003871 name_len++; /* account for buffer type byte */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003872 inc_rfc1001_len(pSMB, (__u16)name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07003873 pSMB->ByteCount = cpu_to_le16(name_len);
3874
3875 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003876 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003877 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003878 cFYI(1, "Send error in QueryInfo = %d", rc);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003879 } else if (data) {
Steve French1bd5bbc2006-09-28 03:35:57 +00003880 struct timespec ts;
3881 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00003882
3883 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003884 /* BB FIXME - add time zone adjustment BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003885 memset(data, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003886 ts.tv_nsec = 0;
3887 ts.tv_sec = time;
3888 /* decode time fields */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003889 data->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
3890 data->LastWriteTime = data->ChangeTime;
3891 data->LastAccessTime = 0;
3892 data->AllocationSize =
Steve French70ca7342005-09-22 16:32:06 -07003893 cpu_to_le64(le32_to_cpu(pSMBr->size));
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003894 data->EndOfFile = data->AllocationSize;
3895 data->Attributes =
Steve French70ca7342005-09-22 16:32:06 -07003896 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003897 } else
3898 rc = -EIO; /* bad buffer passed in */
3899
3900 cifs_buf_release(pSMB);
3901
3902 if (rc == -EAGAIN)
3903 goto QInfRetry;
3904
3905 return rc;
3906}
3907
Jeff Laytonbcd53572010-02-12 07:44:16 -05003908int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003909CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonbcd53572010-02-12 07:44:16 -05003910 u16 netfid, FILE_ALL_INFO *pFindData)
3911{
3912 struct smb_t2_qfi_req *pSMB = NULL;
3913 struct smb_t2_qfi_rsp *pSMBr = NULL;
3914 int rc = 0;
3915 int bytes_returned;
3916 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07003917
Jeff Laytonbcd53572010-02-12 07:44:16 -05003918QFileInfoRetry:
3919 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3920 (void **) &pSMBr);
3921 if (rc)
3922 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07003923
Jeff Laytonbcd53572010-02-12 07:44:16 -05003924 params = 2 /* level */ + 2 /* fid */;
3925 pSMB->t2.TotalDataCount = 0;
3926 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3927 /* BB find exact max data count below from sess structure BB */
3928 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3929 pSMB->t2.MaxSetupCount = 0;
3930 pSMB->t2.Reserved = 0;
3931 pSMB->t2.Flags = 0;
3932 pSMB->t2.Timeout = 0;
3933 pSMB->t2.Reserved2 = 0;
3934 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3935 Fid) - 4);
3936 pSMB->t2.DataCount = 0;
3937 pSMB->t2.DataOffset = 0;
3938 pSMB->t2.SetupCount = 1;
3939 pSMB->t2.Reserved3 = 0;
3940 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3941 byte_count = params + 1 /* pad */ ;
3942 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3943 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3944 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3945 pSMB->Pad = 0;
3946 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003947 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003948
3949 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3950 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3951 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00003952 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003953 } else { /* decode response */
3954 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3955
3956 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3957 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04003958 else if (get_bcc(&pSMBr->hdr) < 40)
Jeff Laytonbcd53572010-02-12 07:44:16 -05003959 rc = -EIO; /* bad smb */
3960 else if (pFindData) {
3961 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3962 memcpy((char *) pFindData,
3963 (char *) &pSMBr->hdr.Protocol +
3964 data_offset, sizeof(FILE_ALL_INFO));
3965 } else
3966 rc = -ENOMEM;
3967 }
3968 cifs_buf_release(pSMB);
3969 if (rc == -EAGAIN)
3970 goto QFileInfoRetry;
3971
3972 return rc;
3973}
Steve French6b8edfe2005-08-23 20:26:03 -07003974
Linus Torvalds1da177e2005-04-16 15:20:36 -07003975int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003976CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003977 const char *search_name, FILE_ALL_INFO *data,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003978 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003979 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003980{
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003981 /* level 263 SMB_QUERY_FILE_ALL_INFO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003982 TRANSACTION2_QPI_REQ *pSMB = NULL;
3983 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3984 int rc = 0;
3985 int bytes_returned;
3986 int name_len;
3987 __u16 params, byte_count;
3988
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003989 /* cFYI(1, "In QPathInfo path %s", search_name); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003990QPathInfoRetry:
3991 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3992 (void **) &pSMBr);
3993 if (rc)
3994 return rc;
3995
3996 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3997 name_len =
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003998 cifsConvertToUTF16((__le16 *) pSMB->FileName, search_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06003999 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004000 name_len++; /* trailing null */
4001 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004002 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004003 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004004 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004005 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004006 }
4007
Steve French50c2f752007-07-13 00:33:32 +00004008 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004009 pSMB->TotalDataCount = 0;
4010 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004011 /* BB find exact max SMB PDU from sess structure BB */
4012 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004013 pSMB->MaxSetupCount = 0;
4014 pSMB->Reserved = 0;
4015 pSMB->Flags = 0;
4016 pSMB->Timeout = 0;
4017 pSMB->Reserved2 = 0;
4018 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004019 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004020 pSMB->DataCount = 0;
4021 pSMB->DataOffset = 0;
4022 pSMB->SetupCount = 1;
4023 pSMB->Reserved3 = 0;
4024 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4025 byte_count = params + 1 /* pad */ ;
4026 pSMB->TotalParameterCount = cpu_to_le16(params);
4027 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00004028 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004029 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
4030 else
4031 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004032 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004033 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004034 pSMB->ByteCount = cpu_to_le16(byte_count);
4035
4036 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4037 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4038 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004039 cFYI(1, "Send error in QPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004040 } else { /* decode response */
4041 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4042
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004043 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4044 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004045 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004046 rc = -EIO; /* bad smb */
Jeff Layton820a8032011-05-04 08:05:26 -04004047 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
Steve French50c2f752007-07-13 00:33:32 +00004048 rc = -EIO; /* 24 or 26 expected but we do not read
4049 last field */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004050 else if (data) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004051 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004052 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00004053
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004054 /*
4055 * On legacy responses we do not read the last field,
4056 * EAsize, fortunately since it varies by subdialect and
4057 * also note it differs on Set vs Get, ie two bytes or 4
4058 * bytes depending but we don't care here.
4059 */
Steve Frenchad7a2922008-02-07 23:25:02 +00004060 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004061 size = sizeof(FILE_INFO_STANDARD);
4062 else
4063 size = sizeof(FILE_ALL_INFO);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004064 memcpy((char *) data, (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004065 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004066 } else
4067 rc = -ENOMEM;
4068 }
4069 cifs_buf_release(pSMB);
4070 if (rc == -EAGAIN)
4071 goto QPathInfoRetry;
4072
4073 return rc;
4074}
4075
4076int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004077CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004078 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
4079{
4080 struct smb_t2_qfi_req *pSMB = NULL;
4081 struct smb_t2_qfi_rsp *pSMBr = NULL;
4082 int rc = 0;
4083 int bytes_returned;
4084 __u16 params, byte_count;
4085
4086UnixQFileInfoRetry:
4087 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4088 (void **) &pSMBr);
4089 if (rc)
4090 return rc;
4091
4092 params = 2 /* level */ + 2 /* fid */;
4093 pSMB->t2.TotalDataCount = 0;
4094 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4095 /* BB find exact max data count below from sess structure BB */
4096 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4097 pSMB->t2.MaxSetupCount = 0;
4098 pSMB->t2.Reserved = 0;
4099 pSMB->t2.Flags = 0;
4100 pSMB->t2.Timeout = 0;
4101 pSMB->t2.Reserved2 = 0;
4102 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4103 Fid) - 4);
4104 pSMB->t2.DataCount = 0;
4105 pSMB->t2.DataOffset = 0;
4106 pSMB->t2.SetupCount = 1;
4107 pSMB->t2.Reserved3 = 0;
4108 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4109 byte_count = params + 1 /* pad */ ;
4110 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4111 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4112 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4113 pSMB->Pad = 0;
4114 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004115 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004116
4117 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4118 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4119 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00004120 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004121 } else { /* decode response */
4122 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4123
Jeff Layton820a8032011-05-04 08:05:26 -04004124 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004125 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response. "
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004126 "Unix Extensions can be disabled on mount "
Steve Frenchf19159d2010-04-21 04:12:10 +00004127 "by specifying the nosfu mount option.");
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004128 rc = -EIO; /* bad smb */
4129 } else {
4130 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4131 memcpy((char *) pFindData,
4132 (char *) &pSMBr->hdr.Protocol +
4133 data_offset,
4134 sizeof(FILE_UNIX_BASIC_INFO));
4135 }
4136 }
4137
4138 cifs_buf_release(pSMB);
4139 if (rc == -EAGAIN)
4140 goto UnixQFileInfoRetry;
4141
4142 return rc;
4143}
4144
4145int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004146CIFSSMBUnixQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004147 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00004148 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07004149 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004150{
4151/* SMB_QUERY_FILE_UNIX_BASIC */
4152 TRANSACTION2_QPI_REQ *pSMB = NULL;
4153 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4154 int rc = 0;
4155 int bytes_returned = 0;
4156 int name_len;
4157 __u16 params, byte_count;
4158
Joe Perchesb6b38f72010-04-21 03:50:45 +00004159 cFYI(1, "In QPathInfo (Unix) the path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004160UnixQPathInfoRetry:
4161 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4162 (void **) &pSMBr);
4163 if (rc)
4164 return rc;
4165
4166 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4167 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004168 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4169 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004170 name_len++; /* trailing null */
4171 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004172 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004173 name_len = strnlen(searchName, PATH_MAX);
4174 name_len++; /* trailing null */
4175 strncpy(pSMB->FileName, searchName, name_len);
4176 }
4177
Steve French50c2f752007-07-13 00:33:32 +00004178 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004179 pSMB->TotalDataCount = 0;
4180 pSMB->MaxParameterCount = cpu_to_le16(2);
4181 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00004182 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004183 pSMB->MaxSetupCount = 0;
4184 pSMB->Reserved = 0;
4185 pSMB->Flags = 0;
4186 pSMB->Timeout = 0;
4187 pSMB->Reserved2 = 0;
4188 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004189 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004190 pSMB->DataCount = 0;
4191 pSMB->DataOffset = 0;
4192 pSMB->SetupCount = 1;
4193 pSMB->Reserved3 = 0;
4194 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4195 byte_count = params + 1 /* pad */ ;
4196 pSMB->TotalParameterCount = cpu_to_le16(params);
4197 pSMB->ParameterCount = pSMB->TotalParameterCount;
4198 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4199 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004200 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004201 pSMB->ByteCount = cpu_to_le16(byte_count);
4202
4203 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4204 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4205 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004206 cFYI(1, "Send error in QPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004207 } else { /* decode response */
4208 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4209
Jeff Layton820a8032011-05-04 08:05:26 -04004210 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004211 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response. "
Steve French1e71f252007-09-20 15:30:07 +00004212 "Unix Extensions can be disabled on mount "
Joe Perchesb6b38f72010-04-21 03:50:45 +00004213 "by specifying the nosfu mount option.");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004214 rc = -EIO; /* bad smb */
4215 } else {
4216 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4217 memcpy((char *) pFindData,
4218 (char *) &pSMBr->hdr.Protocol +
4219 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00004220 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004221 }
4222 }
4223 cifs_buf_release(pSMB);
4224 if (rc == -EAGAIN)
4225 goto UnixQPathInfoRetry;
4226
4227 return rc;
4228}
4229
Linus Torvalds1da177e2005-04-16 15:20:36 -07004230/* xid, tcon, searchName and codepage are input parms, rest are returned */
4231int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004232CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004233 const char *searchName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004234 const struct nls_table *nls_codepage,
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004235 __u16 *pnetfid, __u16 search_flags,
Steve French50c2f752007-07-13 00:33:32 +00004236 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004237{
4238/* level 257 SMB_ */
4239 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
4240 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004241 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004242 int rc = 0;
4243 int bytes_returned = 0;
4244 int name_len;
4245 __u16 params, byte_count;
4246
Joe Perchesb6b38f72010-04-21 03:50:45 +00004247 cFYI(1, "In FindFirst for %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004248
4249findFirstRetry:
4250 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4251 (void **) &pSMBr);
4252 if (rc)
4253 return rc;
4254
4255 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4256 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004257 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4258 PATH_MAX, nls_codepage, remap);
Steve French737b7582005-04-28 22:41:06 -07004259 /* We can not add the asterik earlier in case
4260 it got remapped to 0xF03A as if it were part of the
4261 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004262 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07004263 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07004264 pSMB->FileName[name_len+1] = 0;
4265 pSMB->FileName[name_len+2] = '*';
4266 pSMB->FileName[name_len+3] = 0;
4267 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004268 pSMB->FileName[name_len] = 0; /* null terminate just in case */
4269 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07004270 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004271 } else { /* BB add check for overrun of SMB buf BB */
4272 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004273/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00004274 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004275 free buffer exit; BB */
4276 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07004277 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07004278 pSMB->FileName[name_len+1] = '*';
4279 pSMB->FileName[name_len+2] = 0;
4280 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004281 }
4282
4283 params = 12 + name_len /* includes null */ ;
4284 pSMB->TotalDataCount = 0; /* no EAs */
4285 pSMB->MaxParameterCount = cpu_to_le16(10);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004286 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004287 pSMB->MaxSetupCount = 0;
4288 pSMB->Reserved = 0;
4289 pSMB->Flags = 0;
4290 pSMB->Timeout = 0;
4291 pSMB->Reserved2 = 0;
4292 byte_count = params + 1 /* pad */ ;
4293 pSMB->TotalParameterCount = cpu_to_le16(params);
4294 pSMB->ParameterCount = pSMB->TotalParameterCount;
4295 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00004296 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
4297 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004298 pSMB->DataCount = 0;
4299 pSMB->DataOffset = 0;
4300 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
4301 pSMB->Reserved3 = 0;
4302 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
4303 pSMB->SearchAttributes =
4304 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
4305 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00004306 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004307 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004308 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4309
4310 /* BB what should we set StorageType to? Does it matter? BB */
4311 pSMB->SearchStorageType = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004312 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004313 pSMB->ByteCount = cpu_to_le16(byte_count);
4314
4315 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4316 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004317 cifs_stats_inc(&tcon->stats.cifs_stats.num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004318
Steve French88274812006-03-09 22:21:45 +00004319 if (rc) {/* BB add logic to retry regular search if Unix search
4320 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004321 /* BB Add code to handle unsupported level rc */
Joe Perchesb6b38f72010-04-21 03:50:45 +00004322 cFYI(1, "Error in FindFirst = %d", rc);
Steve French1982c342005-08-17 12:38:22 -07004323
Steve French88274812006-03-09 22:21:45 +00004324 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004325
4326 /* BB eventually could optimize out free and realloc of buf */
4327 /* for this case */
4328 if (rc == -EAGAIN)
4329 goto findFirstRetry;
4330 } else { /* decode response */
4331 /* BB remember to free buffer if error BB */
4332 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00004333 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004334 unsigned int lnoff;
4335
Linus Torvalds1da177e2005-04-16 15:20:36 -07004336 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004337 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004338 else
Steve French4b18f2a2008-04-29 00:06:05 +00004339 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004340
4341 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004342 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00004343 psrch_inf->srch_entries_start =
4344 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004345 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004346 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
4347 le16_to_cpu(pSMBr->t2.ParameterOffset));
4348
Steve French790fe572007-07-07 19:25:05 +00004349 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004350 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004351 else
Steve French4b18f2a2008-04-29 00:06:05 +00004352 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004353
Steve French50c2f752007-07-13 00:33:32 +00004354 psrch_inf->entries_in_buffer =
4355 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00004356 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004357 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004358 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004359 if (CIFSMaxBufSize < lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004360 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00004361 psrch_inf->last_entry = NULL;
4362 return rc;
4363 }
4364
Steve French0752f152008-10-07 20:03:33 +00004365 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00004366 lnoff;
4367
Linus Torvalds1da177e2005-04-16 15:20:36 -07004368 *pnetfid = parms->SearchHandle;
4369 } else {
4370 cifs_buf_release(pSMB);
4371 }
4372 }
4373
4374 return rc;
4375}
4376
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004377int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
4378 __u16 searchHandle, __u16 search_flags,
4379 struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004380{
4381 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
4382 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004383 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004384 char *response_data;
4385 int rc = 0;
Jeff Layton9438fab2011-08-23 07:21:28 -04004386 int bytes_returned;
4387 unsigned int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004388 __u16 params, byte_count;
4389
Joe Perchesb6b38f72010-04-21 03:50:45 +00004390 cFYI(1, "In FindNext");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004391
Steve French4b18f2a2008-04-29 00:06:05 +00004392 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004393 return -ENOENT;
4394
4395 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4396 (void **) &pSMBr);
4397 if (rc)
4398 return rc;
4399
Steve French50c2f752007-07-13 00:33:32 +00004400 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004401 byte_count = 0;
4402 pSMB->TotalDataCount = 0; /* no EAs */
4403 pSMB->MaxParameterCount = cpu_to_le16(8);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004404 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004405 pSMB->MaxSetupCount = 0;
4406 pSMB->Reserved = 0;
4407 pSMB->Flags = 0;
4408 pSMB->Timeout = 0;
4409 pSMB->Reserved2 = 0;
4410 pSMB->ParameterOffset = cpu_to_le16(
4411 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
4412 pSMB->DataCount = 0;
4413 pSMB->DataOffset = 0;
4414 pSMB->SetupCount = 1;
4415 pSMB->Reserved3 = 0;
4416 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
4417 pSMB->SearchHandle = searchHandle; /* always kept as le */
4418 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00004419 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004420 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4421 pSMB->ResumeKey = psrch_inf->resume_key;
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004422 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004423
4424 name_len = psrch_inf->resume_name_len;
4425 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00004426 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004427 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
4428 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07004429 /* 14 byte parm len above enough for 2 byte null terminator */
4430 pSMB->ResumeFileName[name_len] = 0;
4431 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004432 } else {
4433 rc = -EINVAL;
4434 goto FNext2_err_exit;
4435 }
4436 byte_count = params + 1 /* pad */ ;
4437 pSMB->TotalParameterCount = cpu_to_le16(params);
4438 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004439 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004440 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004441
Linus Torvalds1da177e2005-04-16 15:20:36 -07004442 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4443 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004444 cifs_stats_inc(&tcon->stats.cifs_stats.num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004445 if (rc) {
4446 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00004447 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07004448 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00004449 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004450 } else
Joe Perchesb6b38f72010-04-21 03:50:45 +00004451 cFYI(1, "FindNext returned = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004452 } else { /* decode response */
4453 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00004454
Steve French790fe572007-07-07 19:25:05 +00004455 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004456 unsigned int lnoff;
4457
Linus Torvalds1da177e2005-04-16 15:20:36 -07004458 /* BB fixme add lock for file (srch_info) struct here */
4459 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004460 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004461 else
Steve French4b18f2a2008-04-29 00:06:05 +00004462 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004463 response_data = (char *) &pSMBr->hdr.Protocol +
4464 le16_to_cpu(pSMBr->t2.ParameterOffset);
4465 parms = (T2_FNEXT_RSP_PARMS *)response_data;
4466 response_data = (char *)&pSMBr->hdr.Protocol +
4467 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00004468 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00004469 cifs_small_buf_release(
4470 psrch_inf->ntwrk_buf_start);
4471 else
4472 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004473 psrch_inf->srch_entries_start = response_data;
4474 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004475 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00004476 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004477 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004478 else
Steve French4b18f2a2008-04-29 00:06:05 +00004479 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00004480 psrch_inf->entries_in_buffer =
4481 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004482 psrch_inf->index_of_last_entry +=
4483 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004484 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004485 if (CIFSMaxBufSize < lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004486 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00004487 psrch_inf->last_entry = NULL;
4488 return rc;
4489 } else
4490 psrch_inf->last_entry =
4491 psrch_inf->srch_entries_start + lnoff;
4492
Joe Perchesb6b38f72010-04-21 03:50:45 +00004493/* cFYI(1, "fnxt2 entries in buf %d index_of_last %d",
4494 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004495
4496 /* BB fixme add unlock here */
4497 }
4498
4499 }
4500
4501 /* BB On error, should we leave previous search buf (and count and
4502 last entry fields) intact or free the previous one? */
4503
4504 /* Note: On -EAGAIN error only caller can retry on handle based calls
4505 since file handle passed in no longer valid */
4506FNext2_err_exit:
4507 if (rc != 0)
4508 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004509 return rc;
4510}
4511
4512int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004513CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004514 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004515{
4516 int rc = 0;
4517 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004518
Joe Perchesb6b38f72010-04-21 03:50:45 +00004519 cFYI(1, "In CIFSSMBFindClose");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004520 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
4521
4522 /* no sense returning error if session restarted
4523 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00004524 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004525 return 0;
4526 if (rc)
4527 return rc;
4528
Linus Torvalds1da177e2005-04-16 15:20:36 -07004529 pSMB->FileID = searchHandle;
4530 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04004531 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004532 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00004533 cERROR(1, "Send error in FindClose = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00004534
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004535 cifs_stats_inc(&tcon->stats.cifs_stats.num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004536
4537 /* Since session is dead, search handle closed on server already */
4538 if (rc == -EAGAIN)
4539 rc = 0;
4540
4541 return rc;
4542}
4543
Linus Torvalds1da177e2005-04-16 15:20:36 -07004544int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004545CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004546 const char *search_name, __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00004547 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004548{
4549 int rc = 0;
4550 TRANSACTION2_QPI_REQ *pSMB = NULL;
4551 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4552 int name_len, bytes_returned;
4553 __u16 params, byte_count;
4554
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004555 cFYI(1, "In GetSrvInodeNum for %s", search_name);
Steve French790fe572007-07-07 19:25:05 +00004556 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00004557 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004558
4559GetInodeNumberRetry:
4560 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004561 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004562 if (rc)
4563 return rc;
4564
Linus Torvalds1da177e2005-04-16 15:20:36 -07004565 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4566 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004567 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004568 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004569 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004570 name_len++; /* trailing null */
4571 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004572 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004573 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004574 name_len++; /* trailing null */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004575 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004576 }
4577
4578 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4579 pSMB->TotalDataCount = 0;
4580 pSMB->MaxParameterCount = cpu_to_le16(2);
4581 /* BB find exact max data count below from sess structure BB */
4582 pSMB->MaxDataCount = cpu_to_le16(4000);
4583 pSMB->MaxSetupCount = 0;
4584 pSMB->Reserved = 0;
4585 pSMB->Flags = 0;
4586 pSMB->Timeout = 0;
4587 pSMB->Reserved2 = 0;
4588 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004589 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004590 pSMB->DataCount = 0;
4591 pSMB->DataOffset = 0;
4592 pSMB->SetupCount = 1;
4593 pSMB->Reserved3 = 0;
4594 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4595 byte_count = params + 1 /* pad */ ;
4596 pSMB->TotalParameterCount = cpu_to_le16(params);
4597 pSMB->ParameterCount = pSMB->TotalParameterCount;
4598 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4599 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004600 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004601 pSMB->ByteCount = cpu_to_le16(byte_count);
4602
4603 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4604 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4605 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004606 cFYI(1, "error %d in QueryInternalInfo", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004607 } else {
4608 /* decode response */
4609 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004610 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04004611 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004612 /* If rc should we check for EOPNOSUPP and
4613 disable the srvino flag? or in caller? */
4614 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00004615 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004616 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4617 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00004618 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004619 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00004620 if (count < 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004621 cFYI(1, "Illegal size ret in QryIntrnlInf");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004622 rc = -EIO;
4623 goto GetInodeNumOut;
4624 }
4625 pfinfo = (struct file_internal_info *)
4626 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00004627 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004628 }
4629 }
4630GetInodeNumOut:
4631 cifs_buf_release(pSMB);
4632 if (rc == -EAGAIN)
4633 goto GetInodeNumberRetry;
4634 return rc;
4635}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004636
Igor Mammedovfec45852008-05-16 13:06:30 +04004637/* parses DFS refferal V3 structure
4638 * caller is responsible for freeing target_nodes
4639 * returns:
4640 * on success - 0
4641 * on failure - errno
4642 */
4643static int
Steve Frencha1fe78f2008-05-16 18:48:38 +00004644parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
Igor Mammedovfec45852008-05-16 13:06:30 +04004645 unsigned int *num_of_nodes,
4646 struct dfs_info3_param **target_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004647 const struct nls_table *nls_codepage, int remap,
4648 const char *searchName)
Igor Mammedovfec45852008-05-16 13:06:30 +04004649{
4650 int i, rc = 0;
4651 char *data_end;
4652 bool is_unicode;
4653 struct dfs_referral_level_3 *ref;
4654
Harvey Harrison5ca33c62008-07-23 17:45:58 -07004655 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4656 is_unicode = true;
4657 else
4658 is_unicode = false;
Igor Mammedovfec45852008-05-16 13:06:30 +04004659 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
4660
4661 if (*num_of_nodes < 1) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004662 cERROR(1, "num_referrals: must be at least > 0,"
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004663 "but we get num_referrals = %d", *num_of_nodes);
Igor Mammedovfec45852008-05-16 13:06:30 +04004664 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004665 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004666 }
4667
4668 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
Al Viro1d92cfd2008-06-02 10:59:02 +01004669 if (ref->VersionNumber != cpu_to_le16(3)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004670 cERROR(1, "Referrals of V%d version are not supported,"
4671 "should be V3", le16_to_cpu(ref->VersionNumber));
Igor Mammedovfec45852008-05-16 13:06:30 +04004672 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004673 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004674 }
4675
4676 /* get the upper boundary of the resp buffer */
4677 data_end = (char *)(&(pSMBr->PathConsumed)) +
4678 le16_to_cpu(pSMBr->t2.DataCount);
4679
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004680 cFYI(1, "num_referrals: %d dfs flags: 0x%x ...",
Igor Mammedovfec45852008-05-16 13:06:30 +04004681 *num_of_nodes,
Joe Perchesb6b38f72010-04-21 03:50:45 +00004682 le32_to_cpu(pSMBr->DFSFlags));
Igor Mammedovfec45852008-05-16 13:06:30 +04004683
4684 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
4685 *num_of_nodes, GFP_KERNEL);
4686 if (*target_nodes == NULL) {
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004687 cERROR(1, "Failed to allocate buffer for target_nodes");
Igor Mammedovfec45852008-05-16 13:06:30 +04004688 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004689 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004690 }
4691
Daniel Mack3ad2f3f2010-02-03 08:01:28 +08004692 /* collect necessary data from referrals */
Igor Mammedovfec45852008-05-16 13:06:30 +04004693 for (i = 0; i < *num_of_nodes; i++) {
4694 char *temp;
4695 int max_len;
4696 struct dfs_info3_param *node = (*target_nodes)+i;
4697
Steve French0e0d2cf2009-05-01 05:27:32 +00004698 node->flags = le32_to_cpu(pSMBr->DFSFlags);
Igor Mammedov2c556082008-10-23 13:58:42 +04004699 if (is_unicode) {
Jeff Layton331c3132008-12-17 06:31:53 -05004700 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4701 GFP_KERNEL);
Steve French2920ee22009-08-31 15:27:26 +00004702 if (tmp == NULL) {
4703 rc = -ENOMEM;
4704 goto parse_DFS_referrals_exit;
4705 }
Steve Frenchacbbb762012-01-18 22:32:33 -06004706 cifsConvertToUTF16((__le16 *) tmp, searchName,
4707 PATH_MAX, nls_codepage, remap);
4708 node->path_consumed = cifs_utf16_bytes(tmp,
Jeff Layton69f801f2009-04-30 06:46:32 -04004709 le16_to_cpu(pSMBr->PathConsumed),
Igor Mammedov2c556082008-10-23 13:58:42 +04004710 nls_codepage);
4711 kfree(tmp);
4712 } else
4713 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4714
Igor Mammedovfec45852008-05-16 13:06:30 +04004715 node->server_type = le16_to_cpu(ref->ServerType);
4716 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4717
4718 /* copy DfsPath */
4719 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4720 max_len = data_end - temp;
Steve Frenchacbbb762012-01-18 22:32:33 -06004721 node->path_name = cifs_strndup_from_utf16(temp, max_len,
4722 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004723 if (!node->path_name) {
4724 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004725 goto parse_DFS_referrals_exit;
Jeff Layton066ce682009-04-30 07:16:14 -04004726 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004727
4728 /* copy link target UNC */
4729 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4730 max_len = data_end - temp;
Steve Frenchacbbb762012-01-18 22:32:33 -06004731 node->node_name = cifs_strndup_from_utf16(temp, max_len,
4732 is_unicode, nls_codepage);
Stefan Metzmacherd8f27992012-05-04 00:19:28 +02004733 if (!node->node_name) {
Jeff Laytond8e2f532009-05-14 07:46:59 -04004734 rc = -ENOMEM;
Stefan Metzmacherd8f27992012-05-04 00:19:28 +02004735 goto parse_DFS_referrals_exit;
4736 }
4737
4738 ref++;
Igor Mammedovfec45852008-05-16 13:06:30 +04004739 }
4740
Steve Frencha1fe78f2008-05-16 18:48:38 +00004741parse_DFS_referrals_exit:
Igor Mammedovfec45852008-05-16 13:06:30 +04004742 if (rc) {
4743 free_dfs_info_array(*target_nodes, *num_of_nodes);
4744 *target_nodes = NULL;
4745 *num_of_nodes = 0;
4746 }
4747 return rc;
4748}
4749
Linus Torvalds1da177e2005-04-16 15:20:36 -07004750int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004751CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004752 const char *search_name, struct dfs_info3_param **target_nodes,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004753 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004754 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004755{
4756/* TRANS2_GET_DFS_REFERRAL */
4757 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4758 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004759 int rc = 0;
4760 int bytes_returned;
4761 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004762 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004763 *num_of_nodes = 0;
4764 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004765
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004766 cFYI(1, "In GetDFSRefer the path %s", search_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004767 if (ses == NULL)
4768 return -ENODEV;
4769getDFSRetry:
4770 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4771 (void **) &pSMBr);
4772 if (rc)
4773 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004774
4775 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004776 but should never be null here anyway */
Pavel Shilovsky88257362012-05-23 14:01:59 +04004777 pSMB->hdr.Mid = get_next_mid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004778 pSMB->hdr.Tid = ses->ipc_tid;
4779 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004780 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004781 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004782 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004783 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004784
4785 if (ses->capabilities & CAP_UNICODE) {
4786 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4787 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004788 cifsConvertToUTF16((__le16 *) pSMB->RequestFileName,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004789 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004790 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004791 name_len++; /* trailing null */
4792 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004793 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004794 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004795 name_len++; /* trailing null */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004796 strncpy(pSMB->RequestFileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004797 }
4798
Steve French790fe572007-07-07 19:25:05 +00004799 if (ses->server) {
Steve French96daf2b2011-05-27 04:34:02 +00004800 if (ses->server->sec_mode &
Steve French1a4e15a2006-10-12 21:33:51 +00004801 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4802 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4803 }
4804
Steve French50c2f752007-07-13 00:33:32 +00004805 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004806
Linus Torvalds1da177e2005-04-16 15:20:36 -07004807 params = 2 /* level */ + name_len /*includes null */ ;
4808 pSMB->TotalDataCount = 0;
4809 pSMB->DataCount = 0;
4810 pSMB->DataOffset = 0;
4811 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004812 /* BB find exact max SMB PDU from sess structure BB */
4813 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004814 pSMB->MaxSetupCount = 0;
4815 pSMB->Reserved = 0;
4816 pSMB->Flags = 0;
4817 pSMB->Timeout = 0;
4818 pSMB->Reserved2 = 0;
4819 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004820 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004821 pSMB->SetupCount = 1;
4822 pSMB->Reserved3 = 0;
4823 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4824 byte_count = params + 3 /* pad */ ;
4825 pSMB->ParameterCount = cpu_to_le16(params);
4826 pSMB->TotalParameterCount = pSMB->ParameterCount;
4827 pSMB->MaxReferralLevel = cpu_to_le16(3);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004828 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004829 pSMB->ByteCount = cpu_to_le16(byte_count);
4830
4831 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4832 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4833 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004834 cFYI(1, "Send error in GetDFSRefer = %d", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004835 goto GetDFSRefExit;
4836 }
4837 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004838
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004839 /* BB Also check if enough total bytes returned? */
Jeff Layton820a8032011-05-04 08:05:26 -04004840 if (rc || get_bcc(&pSMBr->hdr) < 17) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004841 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004842 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004843 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004844
Joe Perchesb6b38f72010-04-21 03:50:45 +00004845 cFYI(1, "Decoding GetDFSRefer response BCC: %d Offset %d",
Jeff Layton820a8032011-05-04 08:05:26 -04004846 get_bcc(&pSMBr->hdr),
Joe Perchesb6b38f72010-04-21 03:50:45 +00004847 le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04004848
4849 /* parse returned result into more usable form */
Steve Frencha1fe78f2008-05-16 18:48:38 +00004850 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004851 target_nodes, nls_codepage, remap,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004852 search_name);
Igor Mammedovfec45852008-05-16 13:06:30 +04004853
Linus Torvalds1da177e2005-04-16 15:20:36 -07004854GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004855 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004856
4857 if (rc == -EAGAIN)
4858 goto getDFSRetry;
4859
4860 return rc;
4861}
4862
Steve French20962432005-09-21 22:05:57 -07004863/* Query File System Info such as free space to old servers such as Win 9x */
4864int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004865SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4866 struct kstatfs *FSData)
Steve French20962432005-09-21 22:05:57 -07004867{
4868/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4869 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4870 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4871 FILE_SYSTEM_ALLOC_INFO *response_data;
4872 int rc = 0;
4873 int bytes_returned = 0;
4874 __u16 params, byte_count;
4875
Joe Perchesb6b38f72010-04-21 03:50:45 +00004876 cFYI(1, "OldQFSInfo");
Steve French20962432005-09-21 22:05:57 -07004877oldQFSInfoRetry:
4878 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4879 (void **) &pSMBr);
4880 if (rc)
4881 return rc;
Steve French20962432005-09-21 22:05:57 -07004882
4883 params = 2; /* level */
4884 pSMB->TotalDataCount = 0;
4885 pSMB->MaxParameterCount = cpu_to_le16(2);
4886 pSMB->MaxDataCount = cpu_to_le16(1000);
4887 pSMB->MaxSetupCount = 0;
4888 pSMB->Reserved = 0;
4889 pSMB->Flags = 0;
4890 pSMB->Timeout = 0;
4891 pSMB->Reserved2 = 0;
4892 byte_count = params + 1 /* pad */ ;
4893 pSMB->TotalParameterCount = cpu_to_le16(params);
4894 pSMB->ParameterCount = pSMB->TotalParameterCount;
4895 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4896 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4897 pSMB->DataCount = 0;
4898 pSMB->DataOffset = 0;
4899 pSMB->SetupCount = 1;
4900 pSMB->Reserved3 = 0;
4901 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4902 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004903 inc_rfc1001_len(pSMB, byte_count);
Steve French20962432005-09-21 22:05:57 -07004904 pSMB->ByteCount = cpu_to_le16(byte_count);
4905
4906 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4907 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4908 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004909 cFYI(1, "Send error in QFSInfo = %d", rc);
Steve French20962432005-09-21 22:05:57 -07004910 } else { /* decode response */
4911 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4912
Jeff Layton820a8032011-05-04 08:05:26 -04004913 if (rc || get_bcc(&pSMBr->hdr) < 18)
Steve French20962432005-09-21 22:05:57 -07004914 rc = -EIO; /* bad smb */
4915 else {
4916 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004917 cFYI(1, "qfsinf resp BCC: %d Offset %d",
Jeff Layton820a8032011-05-04 08:05:26 -04004918 get_bcc(&pSMBr->hdr), data_offset);
Steve French20962432005-09-21 22:05:57 -07004919
Steve French50c2f752007-07-13 00:33:32 +00004920 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004921 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4922 FSData->f_bsize =
4923 le16_to_cpu(response_data->BytesPerSector) *
4924 le32_to_cpu(response_data->
4925 SectorsPerAllocationUnit);
4926 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004927 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004928 FSData->f_bfree = FSData->f_bavail =
4929 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004930 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
4931 (unsigned long long)FSData->f_blocks,
4932 (unsigned long long)FSData->f_bfree,
4933 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07004934 }
4935 }
4936 cifs_buf_release(pSMB);
4937
4938 if (rc == -EAGAIN)
4939 goto oldQFSInfoRetry;
4940
4941 return rc;
4942}
4943
Linus Torvalds1da177e2005-04-16 15:20:36 -07004944int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004945CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4946 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004947{
4948/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4949 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4950 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4951 FILE_SYSTEM_INFO *response_data;
4952 int rc = 0;
4953 int bytes_returned = 0;
4954 __u16 params, byte_count;
4955
Joe Perchesb6b38f72010-04-21 03:50:45 +00004956 cFYI(1, "In QFSInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004957QFSInfoRetry:
4958 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4959 (void **) &pSMBr);
4960 if (rc)
4961 return rc;
4962
4963 params = 2; /* level */
4964 pSMB->TotalDataCount = 0;
4965 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004966 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004967 pSMB->MaxSetupCount = 0;
4968 pSMB->Reserved = 0;
4969 pSMB->Flags = 0;
4970 pSMB->Timeout = 0;
4971 pSMB->Reserved2 = 0;
4972 byte_count = params + 1 /* pad */ ;
4973 pSMB->TotalParameterCount = cpu_to_le16(params);
4974 pSMB->ParameterCount = pSMB->TotalParameterCount;
4975 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004976 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004977 pSMB->DataCount = 0;
4978 pSMB->DataOffset = 0;
4979 pSMB->SetupCount = 1;
4980 pSMB->Reserved3 = 0;
4981 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4982 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004983 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004984 pSMB->ByteCount = cpu_to_le16(byte_count);
4985
4986 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4987 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4988 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004989 cFYI(1, "Send error in QFSInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004990 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00004991 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004992
Jeff Layton820a8032011-05-04 08:05:26 -04004993 if (rc || get_bcc(&pSMBr->hdr) < 24)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004994 rc = -EIO; /* bad smb */
4995 else {
4996 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004997
4998 response_data =
4999 (FILE_SYSTEM_INFO
5000 *) (((char *) &pSMBr->hdr.Protocol) +
5001 data_offset);
5002 FSData->f_bsize =
5003 le32_to_cpu(response_data->BytesPerSector) *
5004 le32_to_cpu(response_data->
5005 SectorsPerAllocationUnit);
5006 FSData->f_blocks =
5007 le64_to_cpu(response_data->TotalAllocationUnits);
5008 FSData->f_bfree = FSData->f_bavail =
5009 le64_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesb6b38f72010-04-21 03:50:45 +00005010 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
5011 (unsigned long long)FSData->f_blocks,
5012 (unsigned long long)FSData->f_bfree,
5013 FSData->f_bsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005014 }
5015 }
5016 cifs_buf_release(pSMB);
5017
5018 if (rc == -EAGAIN)
5019 goto QFSInfoRetry;
5020
5021 return rc;
5022}
5023
5024int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005025CIFSSMBQFSAttributeInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005026{
5027/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
5028 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5029 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5030 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
5031 int rc = 0;
5032 int bytes_returned = 0;
5033 __u16 params, byte_count;
5034
Joe Perchesb6b38f72010-04-21 03:50:45 +00005035 cFYI(1, "In QFSAttributeInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005036QFSAttributeRetry:
5037 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5038 (void **) &pSMBr);
5039 if (rc)
5040 return rc;
5041
5042 params = 2; /* level */
5043 pSMB->TotalDataCount = 0;
5044 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005045 /* BB find exact max SMB PDU from sess structure BB */
5046 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005047 pSMB->MaxSetupCount = 0;
5048 pSMB->Reserved = 0;
5049 pSMB->Flags = 0;
5050 pSMB->Timeout = 0;
5051 pSMB->Reserved2 = 0;
5052 byte_count = params + 1 /* pad */ ;
5053 pSMB->TotalParameterCount = cpu_to_le16(params);
5054 pSMB->ParameterCount = pSMB->TotalParameterCount;
5055 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005056 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005057 pSMB->DataCount = 0;
5058 pSMB->DataOffset = 0;
5059 pSMB->SetupCount = 1;
5060 pSMB->Reserved3 = 0;
5061 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5062 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005063 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005064 pSMB->ByteCount = cpu_to_le16(byte_count);
5065
5066 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5067 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5068 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005069 cERROR(1, "Send error in QFSAttributeInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005070 } else { /* decode response */
5071 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5072
Jeff Layton820a8032011-05-04 08:05:26 -04005073 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Steve French50c2f752007-07-13 00:33:32 +00005074 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005075 rc = -EIO; /* bad smb */
5076 } else {
5077 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5078 response_data =
5079 (FILE_SYSTEM_ATTRIBUTE_INFO
5080 *) (((char *) &pSMBr->hdr.Protocol) +
5081 data_offset);
5082 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005083 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005084 }
5085 }
5086 cifs_buf_release(pSMB);
5087
5088 if (rc == -EAGAIN)
5089 goto QFSAttributeRetry;
5090
5091 return rc;
5092}
5093
5094int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005095CIFSSMBQFSDeviceInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005096{
5097/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
5098 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5099 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5100 FILE_SYSTEM_DEVICE_INFO *response_data;
5101 int rc = 0;
5102 int bytes_returned = 0;
5103 __u16 params, byte_count;
5104
Joe Perchesb6b38f72010-04-21 03:50:45 +00005105 cFYI(1, "In QFSDeviceInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005106QFSDeviceRetry:
5107 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5108 (void **) &pSMBr);
5109 if (rc)
5110 return rc;
5111
5112 params = 2; /* level */
5113 pSMB->TotalDataCount = 0;
5114 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005115 /* BB find exact max SMB PDU from sess structure BB */
5116 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005117 pSMB->MaxSetupCount = 0;
5118 pSMB->Reserved = 0;
5119 pSMB->Flags = 0;
5120 pSMB->Timeout = 0;
5121 pSMB->Reserved2 = 0;
5122 byte_count = params + 1 /* pad */ ;
5123 pSMB->TotalParameterCount = cpu_to_le16(params);
5124 pSMB->ParameterCount = pSMB->TotalParameterCount;
5125 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005126 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005127
5128 pSMB->DataCount = 0;
5129 pSMB->DataOffset = 0;
5130 pSMB->SetupCount = 1;
5131 pSMB->Reserved3 = 0;
5132 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5133 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005134 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005135 pSMB->ByteCount = cpu_to_le16(byte_count);
5136
5137 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5138 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5139 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005140 cFYI(1, "Send error in QFSDeviceInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005141 } else { /* decode response */
5142 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5143
Jeff Layton820a8032011-05-04 08:05:26 -04005144 if (rc || get_bcc(&pSMBr->hdr) <
5145 sizeof(FILE_SYSTEM_DEVICE_INFO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005146 rc = -EIO; /* bad smb */
5147 else {
5148 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5149 response_data =
Steve French737b7582005-04-28 22:41:06 -07005150 (FILE_SYSTEM_DEVICE_INFO *)
5151 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07005152 data_offset);
5153 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005154 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005155 }
5156 }
5157 cifs_buf_release(pSMB);
5158
5159 if (rc == -EAGAIN)
5160 goto QFSDeviceRetry;
5161
5162 return rc;
5163}
5164
5165int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005166CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005167{
5168/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
5169 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5170 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5171 FILE_SYSTEM_UNIX_INFO *response_data;
5172 int rc = 0;
5173 int bytes_returned = 0;
5174 __u16 params, byte_count;
5175
Joe Perchesb6b38f72010-04-21 03:50:45 +00005176 cFYI(1, "In QFSUnixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005177QFSUnixRetry:
Jeff Laytonf5695992010-09-29 15:27:08 -04005178 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5179 (void **) &pSMB, (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005180 if (rc)
5181 return rc;
5182
5183 params = 2; /* level */
5184 pSMB->TotalDataCount = 0;
5185 pSMB->DataCount = 0;
5186 pSMB->DataOffset = 0;
5187 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005188 /* BB find exact max SMB PDU from sess structure BB */
5189 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005190 pSMB->MaxSetupCount = 0;
5191 pSMB->Reserved = 0;
5192 pSMB->Flags = 0;
5193 pSMB->Timeout = 0;
5194 pSMB->Reserved2 = 0;
5195 byte_count = params + 1 /* pad */ ;
5196 pSMB->ParameterCount = cpu_to_le16(params);
5197 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005198 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5199 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005200 pSMB->SetupCount = 1;
5201 pSMB->Reserved3 = 0;
5202 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5203 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005204 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005205 pSMB->ByteCount = cpu_to_le16(byte_count);
5206
5207 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5208 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5209 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005210 cERROR(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005211 } else { /* decode response */
5212 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5213
Jeff Layton820a8032011-05-04 08:05:26 -04005214 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005215 rc = -EIO; /* bad smb */
5216 } else {
5217 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5218 response_data =
5219 (FILE_SYSTEM_UNIX_INFO
5220 *) (((char *) &pSMBr->hdr.Protocol) +
5221 data_offset);
5222 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005223 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005224 }
5225 }
5226 cifs_buf_release(pSMB);
5227
5228 if (rc == -EAGAIN)
5229 goto QFSUnixRetry;
5230
5231
5232 return rc;
5233}
5234
Jeremy Allisonac670552005-06-22 17:26:35 -07005235int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005236CIFSSMBSetFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07005237{
5238/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
5239 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
5240 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
5241 int rc = 0;
5242 int bytes_returned = 0;
5243 __u16 params, param_offset, offset, byte_count;
5244
Joe Perchesb6b38f72010-04-21 03:50:45 +00005245 cFYI(1, "In SETFSUnixInfo");
Jeremy Allisonac670552005-06-22 17:26:35 -07005246SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00005247 /* BB switch to small buf init to save memory */
Jeff Laytonf5695992010-09-29 15:27:08 -04005248 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5249 (void **) &pSMB, (void **) &pSMBr);
Jeremy Allisonac670552005-06-22 17:26:35 -07005250 if (rc)
5251 return rc;
5252
5253 params = 4; /* 2 bytes zero followed by info level. */
5254 pSMB->MaxSetupCount = 0;
5255 pSMB->Reserved = 0;
5256 pSMB->Flags = 0;
5257 pSMB->Timeout = 0;
5258 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00005259 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
5260 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07005261 offset = param_offset + params;
5262
5263 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00005264 /* BB find exact max SMB PDU from sess structure BB */
5265 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07005266 pSMB->SetupCount = 1;
5267 pSMB->Reserved3 = 0;
5268 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
5269 byte_count = 1 /* pad */ + params + 12;
5270
5271 pSMB->DataCount = cpu_to_le16(12);
5272 pSMB->ParameterCount = cpu_to_le16(params);
5273 pSMB->TotalDataCount = pSMB->DataCount;
5274 pSMB->TotalParameterCount = pSMB->ParameterCount;
5275 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5276 pSMB->DataOffset = cpu_to_le16(offset);
5277
5278 /* Params. */
5279 pSMB->FileNum = 0;
5280 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
5281
5282 /* Data. */
5283 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
5284 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
5285 pSMB->ClientUnixCap = cpu_to_le64(cap);
5286
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005287 inc_rfc1001_len(pSMB, byte_count);
Jeremy Allisonac670552005-06-22 17:26:35 -07005288 pSMB->ByteCount = cpu_to_le16(byte_count);
5289
5290 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5291 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5292 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005293 cERROR(1, "Send error in SETFSUnixInfo = %d", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07005294 } else { /* decode response */
5295 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00005296 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07005297 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07005298 }
5299 cifs_buf_release(pSMB);
5300
5301 if (rc == -EAGAIN)
5302 goto SETFSUnixRetry;
5303
5304 return rc;
5305}
5306
5307
Linus Torvalds1da177e2005-04-16 15:20:36 -07005308
5309int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005310CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon,
Steve French737b7582005-04-28 22:41:06 -07005311 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005312{
5313/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
5314 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5315 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5316 FILE_SYSTEM_POSIX_INFO *response_data;
5317 int rc = 0;
5318 int bytes_returned = 0;
5319 __u16 params, byte_count;
5320
Joe Perchesb6b38f72010-04-21 03:50:45 +00005321 cFYI(1, "In QFSPosixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005322QFSPosixRetry:
5323 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5324 (void **) &pSMBr);
5325 if (rc)
5326 return rc;
5327
5328 params = 2; /* level */
5329 pSMB->TotalDataCount = 0;
5330 pSMB->DataCount = 0;
5331 pSMB->DataOffset = 0;
5332 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005333 /* BB find exact max SMB PDU from sess structure BB */
5334 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005335 pSMB->MaxSetupCount = 0;
5336 pSMB->Reserved = 0;
5337 pSMB->Flags = 0;
5338 pSMB->Timeout = 0;
5339 pSMB->Reserved2 = 0;
5340 byte_count = params + 1 /* pad */ ;
5341 pSMB->ParameterCount = cpu_to_le16(params);
5342 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005343 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5344 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005345 pSMB->SetupCount = 1;
5346 pSMB->Reserved3 = 0;
5347 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5348 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005349 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005350 pSMB->ByteCount = cpu_to_le16(byte_count);
5351
5352 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5353 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5354 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005355 cFYI(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005356 } else { /* decode response */
5357 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5358
Jeff Layton820a8032011-05-04 08:05:26 -04005359 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005360 rc = -EIO; /* bad smb */
5361 } else {
5362 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5363 response_data =
5364 (FILE_SYSTEM_POSIX_INFO
5365 *) (((char *) &pSMBr->hdr.Protocol) +
5366 data_offset);
5367 FSData->f_bsize =
5368 le32_to_cpu(response_data->BlockSize);
5369 FSData->f_blocks =
5370 le64_to_cpu(response_data->TotalBlocks);
5371 FSData->f_bfree =
5372 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00005373 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005374 FSData->f_bavail = FSData->f_bfree;
5375 } else {
5376 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00005377 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005378 }
Steve French790fe572007-07-07 19:25:05 +00005379 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005380 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00005381 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00005382 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005383 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00005384 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005385 }
5386 }
5387 cifs_buf_release(pSMB);
5388
5389 if (rc == -EAGAIN)
5390 goto QFSPosixRetry;
5391
5392 return rc;
5393}
5394
5395
Steve French50c2f752007-07-13 00:33:32 +00005396/* We can not use write of zero bytes trick to
5397 set file size due to need for large file support. Also note that
5398 this SetPathInfo is preferred to SetFileInfo based method in next
Linus Torvalds1da177e2005-04-16 15:20:36 -07005399 routine which is only needed to work around a sharing violation bug
5400 in Samba which this routine can run into */
5401
5402int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005403CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
5404 const char *fileName, __u64 size, bool SetAllocation,
Steve French737b7582005-04-28 22:41:06 -07005405 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005406{
5407 struct smb_com_transaction2_spi_req *pSMB = NULL;
5408 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5409 struct file_end_of_file_info *parm_data;
5410 int name_len;
5411 int rc = 0;
5412 int bytes_returned = 0;
5413 __u16 params, byte_count, data_count, param_offset, offset;
5414
Joe Perchesb6b38f72010-04-21 03:50:45 +00005415 cFYI(1, "In SetEOF");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005416SetEOFRetry:
5417 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5418 (void **) &pSMBr);
5419 if (rc)
5420 return rc;
5421
5422 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5423 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005424 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5425 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005426 name_len++; /* trailing null */
5427 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005428 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005429 name_len = strnlen(fileName, PATH_MAX);
5430 name_len++; /* trailing null */
5431 strncpy(pSMB->FileName, fileName, name_len);
5432 }
5433 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005434 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005435 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07005436 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005437 pSMB->MaxSetupCount = 0;
5438 pSMB->Reserved = 0;
5439 pSMB->Flags = 0;
5440 pSMB->Timeout = 0;
5441 pSMB->Reserved2 = 0;
5442 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005443 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005444 offset = param_offset + params;
Steve French790fe572007-07-07 19:25:05 +00005445 if (SetAllocation) {
Steve French50c2f752007-07-13 00:33:32 +00005446 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5447 pSMB->InformationLevel =
5448 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5449 else
5450 pSMB->InformationLevel =
5451 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5452 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005453 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5454 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005455 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005456 else
5457 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005458 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005459 }
5460
5461 parm_data =
5462 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
5463 offset);
5464 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5465 pSMB->DataOffset = cpu_to_le16(offset);
5466 pSMB->SetupCount = 1;
5467 pSMB->Reserved3 = 0;
5468 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5469 byte_count = 3 /* pad */ + params + data_count;
5470 pSMB->DataCount = cpu_to_le16(data_count);
5471 pSMB->TotalDataCount = pSMB->DataCount;
5472 pSMB->ParameterCount = cpu_to_le16(params);
5473 pSMB->TotalParameterCount = pSMB->ParameterCount;
5474 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005475 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005476 parm_data->FileSize = cpu_to_le64(size);
5477 pSMB->ByteCount = cpu_to_le16(byte_count);
5478 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5479 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005480 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005481 cFYI(1, "SetPathInfo (file size) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005482
5483 cifs_buf_release(pSMB);
5484
5485 if (rc == -EAGAIN)
5486 goto SetEOFRetry;
5487
5488 return rc;
5489}
5490
5491int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005492CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon, __u64 size,
Steve French4b18f2a2008-04-29 00:06:05 +00005493 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005494{
5495 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005496 struct file_end_of_file_info *parm_data;
5497 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005498 __u16 params, param_offset, offset, byte_count, count;
5499
Joe Perchesb6b38f72010-04-21 03:50:45 +00005500 cFYI(1, "SetFileSize (via SetFileInfo) %lld",
5501 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07005502 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5503
Linus Torvalds1da177e2005-04-16 15:20:36 -07005504 if (rc)
5505 return rc;
5506
5507 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5508 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005509
Linus Torvalds1da177e2005-04-16 15:20:36 -07005510 params = 6;
5511 pSMB->MaxSetupCount = 0;
5512 pSMB->Reserved = 0;
5513 pSMB->Flags = 0;
5514 pSMB->Timeout = 0;
5515 pSMB->Reserved2 = 0;
5516 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5517 offset = param_offset + params;
5518
Linus Torvalds1da177e2005-04-16 15:20:36 -07005519 count = sizeof(struct file_end_of_file_info);
5520 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005521 /* BB find exact max SMB PDU from sess structure BB */
5522 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005523 pSMB->SetupCount = 1;
5524 pSMB->Reserved3 = 0;
5525 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5526 byte_count = 3 /* pad */ + params + count;
5527 pSMB->DataCount = cpu_to_le16(count);
5528 pSMB->ParameterCount = cpu_to_le16(params);
5529 pSMB->TotalDataCount = pSMB->DataCount;
5530 pSMB->TotalParameterCount = pSMB->ParameterCount;
5531 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5532 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00005533 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
5534 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005535 pSMB->DataOffset = cpu_to_le16(offset);
5536 parm_data->FileSize = cpu_to_le64(size);
5537 pSMB->Fid = fid;
Steve French790fe572007-07-07 19:25:05 +00005538 if (SetAllocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005539 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5540 pSMB->InformationLevel =
5541 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5542 else
5543 pSMB->InformationLevel =
5544 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00005545 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005546 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5547 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005548 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005549 else
5550 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005551 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005552 }
5553 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005554 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005555 pSMB->ByteCount = cpu_to_le16(byte_count);
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005556 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005557 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005558 cFYI(1, "Send error in SetFileInfo (SetFileSize) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005559 }
5560
Steve French50c2f752007-07-13 00:33:32 +00005561 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005562 since file handle passed in no longer valid */
5563
5564 return rc;
5565}
5566
Steve French50c2f752007-07-13 00:33:32 +00005567/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07005568 an open handle, rather than by pathname - this is awkward due to
5569 potential access conflicts on the open, but it is unavoidable for these
5570 old servers since the only other choice is to go from 100 nanosecond DCE
5571 time and resort to the original setpathinfo level which takes the ancient
5572 DOS time format with 2 second granularity */
5573int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005574CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005575 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005576{
5577 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005578 char *data_offset;
5579 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005580 __u16 params, param_offset, offset, byte_count, count;
5581
Joe Perchesb6b38f72010-04-21 03:50:45 +00005582 cFYI(1, "Set Times (via SetFileInfo)");
Steve Frenchcd634992005-04-28 22:41:10 -07005583 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5584
Linus Torvalds1da177e2005-04-16 15:20:36 -07005585 if (rc)
5586 return rc;
5587
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005588 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5589 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005590
Linus Torvalds1da177e2005-04-16 15:20:36 -07005591 params = 6;
5592 pSMB->MaxSetupCount = 0;
5593 pSMB->Reserved = 0;
5594 pSMB->Flags = 0;
5595 pSMB->Timeout = 0;
5596 pSMB->Reserved2 = 0;
5597 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5598 offset = param_offset + params;
5599
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005600 data_offset = (char *)pSMB +
5601 offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005602
Steve French26f57362007-08-30 22:09:15 +00005603 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005604 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005605 /* BB find max SMB PDU from sess */
5606 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005607 pSMB->SetupCount = 1;
5608 pSMB->Reserved3 = 0;
5609 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5610 byte_count = 3 /* pad */ + params + count;
5611 pSMB->DataCount = cpu_to_le16(count);
5612 pSMB->ParameterCount = cpu_to_le16(params);
5613 pSMB->TotalDataCount = pSMB->DataCount;
5614 pSMB->TotalParameterCount = pSMB->ParameterCount;
5615 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5616 pSMB->DataOffset = cpu_to_le16(offset);
5617 pSMB->Fid = fid;
5618 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5619 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5620 else
5621 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5622 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005623 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005624 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005625 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005626 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005627 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005628 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005629
Steve French50c2f752007-07-13 00:33:32 +00005630 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005631 since file handle passed in no longer valid */
5632
5633 return rc;
5634}
5635
Jeff Layton6d22f092008-09-23 11:48:35 -04005636int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005637CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6d22f092008-09-23 11:48:35 -04005638 bool delete_file, __u16 fid, __u32 pid_of_opener)
5639{
5640 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5641 char *data_offset;
5642 int rc = 0;
5643 __u16 params, param_offset, offset, byte_count, count;
5644
Joe Perchesb6b38f72010-04-21 03:50:45 +00005645 cFYI(1, "Set File Disposition (via SetFileInfo)");
Jeff Layton6d22f092008-09-23 11:48:35 -04005646 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5647
5648 if (rc)
5649 return rc;
5650
5651 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5652 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5653
5654 params = 6;
5655 pSMB->MaxSetupCount = 0;
5656 pSMB->Reserved = 0;
5657 pSMB->Flags = 0;
5658 pSMB->Timeout = 0;
5659 pSMB->Reserved2 = 0;
5660 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5661 offset = param_offset + params;
5662
5663 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5664
5665 count = 1;
5666 pSMB->MaxParameterCount = cpu_to_le16(2);
5667 /* BB find max SMB PDU from sess */
5668 pSMB->MaxDataCount = cpu_to_le16(1000);
5669 pSMB->SetupCount = 1;
5670 pSMB->Reserved3 = 0;
5671 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5672 byte_count = 3 /* pad */ + params + count;
5673 pSMB->DataCount = cpu_to_le16(count);
5674 pSMB->ParameterCount = cpu_to_le16(params);
5675 pSMB->TotalDataCount = pSMB->DataCount;
5676 pSMB->TotalParameterCount = pSMB->ParameterCount;
5677 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5678 pSMB->DataOffset = cpu_to_le16(offset);
5679 pSMB->Fid = fid;
5680 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5681 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005682 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton6d22f092008-09-23 11:48:35 -04005683 pSMB->ByteCount = cpu_to_le16(byte_count);
5684 *data_offset = delete_file ? 1 : 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005685 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Jeff Layton6d22f092008-09-23 11:48:35 -04005686 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005687 cFYI(1, "Send error in SetFileDisposition = %d", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005688
5689 return rc;
5690}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005691
5692int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005693CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6fc000e2008-08-02 07:26:12 -04005694 const char *fileName, const FILE_BASIC_INFO *data,
5695 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005696{
5697 TRANSACTION2_SPI_REQ *pSMB = NULL;
5698 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5699 int name_len;
5700 int rc = 0;
5701 int bytes_returned = 0;
5702 char *data_offset;
5703 __u16 params, param_offset, offset, byte_count, count;
5704
Joe Perchesb6b38f72010-04-21 03:50:45 +00005705 cFYI(1, "In SetTimes");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005706
5707SetTimesRetry:
5708 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5709 (void **) &pSMBr);
5710 if (rc)
5711 return rc;
5712
5713 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5714 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005715 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5716 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005717 name_len++; /* trailing null */
5718 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005719 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005720 name_len = strnlen(fileName, PATH_MAX);
5721 name_len++; /* trailing null */
5722 strncpy(pSMB->FileName, fileName, name_len);
5723 }
5724
5725 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005726 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005727 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005728 /* BB find max SMB PDU from sess structure BB */
5729 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005730 pSMB->MaxSetupCount = 0;
5731 pSMB->Reserved = 0;
5732 pSMB->Flags = 0;
5733 pSMB->Timeout = 0;
5734 pSMB->Reserved2 = 0;
5735 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005736 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005737 offset = param_offset + params;
5738 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5739 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5740 pSMB->DataOffset = cpu_to_le16(offset);
5741 pSMB->SetupCount = 1;
5742 pSMB->Reserved3 = 0;
5743 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5744 byte_count = 3 /* pad */ + params + count;
5745
5746 pSMB->DataCount = cpu_to_le16(count);
5747 pSMB->ParameterCount = cpu_to_le16(params);
5748 pSMB->TotalDataCount = pSMB->DataCount;
5749 pSMB->TotalParameterCount = pSMB->ParameterCount;
5750 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5751 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5752 else
5753 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5754 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005755 inc_rfc1001_len(pSMB, byte_count);
Steve French26f57362007-08-30 22:09:15 +00005756 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005757 pSMB->ByteCount = cpu_to_le16(byte_count);
5758 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5759 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005760 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005761 cFYI(1, "SetPathInfo (times) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005762
5763 cifs_buf_release(pSMB);
5764
5765 if (rc == -EAGAIN)
5766 goto SetTimesRetry;
5767
5768 return rc;
5769}
5770
5771/* Can not be used to set time stamps yet (due to old DOS time format) */
5772/* Can be used to set attributes */
5773#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5774 handling it anyway and NT4 was what we thought it would be needed for
5775 Do not delete it until we prove whether needed for Win9x though */
5776int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005777CIFSSMBSetAttrLegacy(unsigned int xid, struct cifs_tcon *tcon, char *fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005778 __u16 dos_attrs, const struct nls_table *nls_codepage)
5779{
5780 SETATTR_REQ *pSMB = NULL;
5781 SETATTR_RSP *pSMBr = NULL;
5782 int rc = 0;
5783 int bytes_returned;
5784 int name_len;
5785
Joe Perchesb6b38f72010-04-21 03:50:45 +00005786 cFYI(1, "In SetAttrLegacy");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005787
5788SetAttrLgcyRetry:
5789 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5790 (void **) &pSMBr);
5791 if (rc)
5792 return rc;
5793
5794 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5795 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005796 ConvertToUTF16((__le16 *) pSMB->fileName, fileName,
5797 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005798 name_len++; /* trailing null */
5799 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005800 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005801 name_len = strnlen(fileName, PATH_MAX);
5802 name_len++; /* trailing null */
5803 strncpy(pSMB->fileName, fileName, name_len);
5804 }
5805 pSMB->attr = cpu_to_le16(dos_attrs);
5806 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005807 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005808 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5809 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5810 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005811 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005812 cFYI(1, "Error in LegacySetAttr = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005813
5814 cifs_buf_release(pSMB);
5815
5816 if (rc == -EAGAIN)
5817 goto SetAttrLgcyRetry;
5818
5819 return rc;
5820}
5821#endif /* temporarily unneeded SetAttr legacy function */
5822
Jeff Layton654cf142009-07-09 20:02:49 -04005823static void
5824cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5825 const struct cifs_unix_set_info_args *args)
5826{
5827 u64 mode = args->mode;
5828
5829 /*
5830 * Samba server ignores set of file size to zero due to bugs in some
5831 * older clients, but we should be precise - we use SetFileSize to
5832 * set file size and do not want to truncate file size to zero
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005833 * accidentally as happened on one Samba server beta by putting
Jeff Layton654cf142009-07-09 20:02:49 -04005834 * zero instead of -1 here
5835 */
5836 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5837 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5838 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5839 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5840 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5841 data_offset->Uid = cpu_to_le64(args->uid);
5842 data_offset->Gid = cpu_to_le64(args->gid);
5843 /* better to leave device as zero when it is */
5844 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5845 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5846 data_offset->Permissions = cpu_to_le64(mode);
5847
5848 if (S_ISREG(mode))
5849 data_offset->Type = cpu_to_le32(UNIX_FILE);
5850 else if (S_ISDIR(mode))
5851 data_offset->Type = cpu_to_le32(UNIX_DIR);
5852 else if (S_ISLNK(mode))
5853 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5854 else if (S_ISCHR(mode))
5855 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5856 else if (S_ISBLK(mode))
5857 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5858 else if (S_ISFIFO(mode))
5859 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5860 else if (S_ISSOCK(mode))
5861 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5862}
5863
Linus Torvalds1da177e2005-04-16 15:20:36 -07005864int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005865CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005866 const struct cifs_unix_set_info_args *args,
5867 u16 fid, u32 pid_of_opener)
5868{
5869 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005870 char *data_offset;
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005871 int rc = 0;
5872 u16 params, param_offset, offset, byte_count, count;
5873
Joe Perchesb6b38f72010-04-21 03:50:45 +00005874 cFYI(1, "Set Unix Info (via SetFileInfo)");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005875 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5876
5877 if (rc)
5878 return rc;
5879
5880 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5881 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5882
5883 params = 6;
5884 pSMB->MaxSetupCount = 0;
5885 pSMB->Reserved = 0;
5886 pSMB->Flags = 0;
5887 pSMB->Timeout = 0;
5888 pSMB->Reserved2 = 0;
5889 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5890 offset = param_offset + params;
5891
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005892 data_offset = (char *)pSMB +
5893 offsetof(struct smb_hdr, Protocol) + offset;
5894
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005895 count = sizeof(FILE_UNIX_BASIC_INFO);
5896
5897 pSMB->MaxParameterCount = cpu_to_le16(2);
5898 /* BB find max SMB PDU from sess */
5899 pSMB->MaxDataCount = cpu_to_le16(1000);
5900 pSMB->SetupCount = 1;
5901 pSMB->Reserved3 = 0;
5902 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5903 byte_count = 3 /* pad */ + params + count;
5904 pSMB->DataCount = cpu_to_le16(count);
5905 pSMB->ParameterCount = cpu_to_le16(params);
5906 pSMB->TotalDataCount = pSMB->DataCount;
5907 pSMB->TotalParameterCount = pSMB->ParameterCount;
5908 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5909 pSMB->DataOffset = cpu_to_le16(offset);
5910 pSMB->Fid = fid;
5911 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5912 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005913 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005914 pSMB->ByteCount = cpu_to_le16(byte_count);
5915
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005916 cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005917
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005918 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005919 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005920 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005921
5922 /* Note: On -EAGAIN error only caller can retry on handle based calls
5923 since file handle passed in no longer valid */
5924
5925 return rc;
5926}
5927
5928int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005929CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005930 const char *file_name,
Jeff Layton01ea95e2009-07-09 20:02:49 -04005931 const struct cifs_unix_set_info_args *args,
5932 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005933{
5934 TRANSACTION2_SPI_REQ *pSMB = NULL;
5935 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5936 int name_len;
5937 int rc = 0;
5938 int bytes_returned = 0;
5939 FILE_UNIX_BASIC_INFO *data_offset;
5940 __u16 params, param_offset, offset, count, byte_count;
5941
Joe Perchesb6b38f72010-04-21 03:50:45 +00005942 cFYI(1, "In SetUID/GID/Mode");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005943setPermsRetry:
5944 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5945 (void **) &pSMBr);
5946 if (rc)
5947 return rc;
5948
5949 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5950 name_len =
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005951 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06005952 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005953 name_len++; /* trailing null */
5954 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005955 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005956 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005957 name_len++; /* trailing null */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005958 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005959 }
5960
5961 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005962 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005963 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005964 /* BB find max SMB PDU from sess structure BB */
5965 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005966 pSMB->MaxSetupCount = 0;
5967 pSMB->Reserved = 0;
5968 pSMB->Flags = 0;
5969 pSMB->Timeout = 0;
5970 pSMB->Reserved2 = 0;
5971 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005972 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005973 offset = param_offset + params;
5974 data_offset =
5975 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5976 offset);
5977 memset(data_offset, 0, count);
5978 pSMB->DataOffset = cpu_to_le16(offset);
5979 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5980 pSMB->SetupCount = 1;
5981 pSMB->Reserved3 = 0;
5982 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5983 byte_count = 3 /* pad */ + params + count;
5984 pSMB->ParameterCount = cpu_to_le16(params);
5985 pSMB->DataCount = cpu_to_le16(count);
5986 pSMB->TotalParameterCount = pSMB->ParameterCount;
5987 pSMB->TotalDataCount = pSMB->DataCount;
5988 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5989 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005990 inc_rfc1001_len(pSMB, byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005991
Jeff Layton654cf142009-07-09 20:02:49 -04005992 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005993
5994 pSMB->ByteCount = cpu_to_le16(byte_count);
5995 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5996 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005997 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005998 cFYI(1, "SetPathInfo (perms) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005999
Steve French0d817bc2008-05-22 02:02:03 +00006000 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006001 if (rc == -EAGAIN)
6002 goto setPermsRetry;
6003 return rc;
6004}
6005
Linus Torvalds1da177e2005-04-16 15:20:36 -07006006#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05006007/*
6008 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
6009 * function used by listxattr and getxattr type calls. When ea_name is set,
6010 * it looks for that attribute name and stuffs that value into the EAData
6011 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
6012 * buffer. In both cases, the return value is either the length of the
6013 * resulting data or a negative error code. If EAData is a NULL pointer then
6014 * the data isn't copied to it, but the length is returned.
6015 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006016ssize_t
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006017CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05006018 const unsigned char *searchName, const unsigned char *ea_name,
6019 char *EAData, size_t buf_size,
6020 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006021{
6022 /* BB assumes one setup word */
6023 TRANSACTION2_QPI_REQ *pSMB = NULL;
6024 TRANSACTION2_QPI_RSP *pSMBr = NULL;
6025 int rc = 0;
6026 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05006027 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006028 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00006029 struct fea *temp_fea;
6030 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006031 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006032 __u16 params, byte_count, data_offset;
Jeff Layton5980fc92011-07-28 12:48:26 -04006033 unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006034
Joe Perchesb6b38f72010-04-21 03:50:45 +00006035 cFYI(1, "In Query All EAs path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006036QAllEAsRetry:
6037 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6038 (void **) &pSMBr);
6039 if (rc)
6040 return rc;
6041
6042 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05006043 list_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006044 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
6045 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05006046 list_len++; /* trailing null */
6047 list_len *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006048 } else { /* BB improve the check for buffer overruns BB */
Jeff Layton6e462b92010-02-10 16:18:26 -05006049 list_len = strnlen(searchName, PATH_MAX);
6050 list_len++; /* trailing null */
6051 strncpy(pSMB->FileName, searchName, list_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006052 }
6053
Jeff Layton6e462b92010-02-10 16:18:26 -05006054 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006055 pSMB->TotalDataCount = 0;
6056 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006057 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05006058 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006059 pSMB->MaxSetupCount = 0;
6060 pSMB->Reserved = 0;
6061 pSMB->Flags = 0;
6062 pSMB->Timeout = 0;
6063 pSMB->Reserved2 = 0;
6064 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00006065 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006066 pSMB->DataCount = 0;
6067 pSMB->DataOffset = 0;
6068 pSMB->SetupCount = 1;
6069 pSMB->Reserved3 = 0;
6070 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
6071 byte_count = params + 1 /* pad */ ;
6072 pSMB->TotalParameterCount = cpu_to_le16(params);
6073 pSMB->ParameterCount = pSMB->TotalParameterCount;
6074 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
6075 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006076 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006077 pSMB->ByteCount = cpu_to_le16(byte_count);
6078
6079 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6080 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6081 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006082 cFYI(1, "Send error in QueryAllEAs = %d", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05006083 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006084 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006085
6086
6087 /* BB also check enough total bytes returned */
6088 /* BB we need to improve the validity checking
6089 of these trans2 responses */
6090
6091 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Jeff Layton820a8032011-05-04 08:05:26 -04006092 if (rc || get_bcc(&pSMBr->hdr) < 4) {
Jeff Laytonf0d38682010-02-10 16:18:26 -05006093 rc = -EIO; /* bad smb */
6094 goto QAllEAsOut;
6095 }
6096
6097 /* check that length of list is not more than bcc */
6098 /* check that each entry does not go beyond length
6099 of list */
6100 /* check that each element of each entry does not
6101 go beyond end of list */
6102 /* validate_trans2_offsets() */
6103 /* BB check if start of smb + data_offset > &bcc+ bcc */
6104
6105 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
6106 ea_response_data = (struct fealist *)
6107 (((char *) &pSMBr->hdr.Protocol) + data_offset);
6108
Jeff Layton6e462b92010-02-10 16:18:26 -05006109 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesb6b38f72010-04-21 03:50:45 +00006110 cFYI(1, "ea length %d", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05006111 if (list_len <= 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006112 cFYI(1, "empty EA list returned from server");
Jeff Laytonf0d38682010-02-10 16:18:26 -05006113 goto QAllEAsOut;
6114 }
6115
Jeff Layton0cd126b2010-02-10 16:18:26 -05006116 /* make sure list_len doesn't go past end of SMB */
Jeff Layton690c5222011-01-20 13:36:51 -05006117 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
Jeff Layton0cd126b2010-02-10 16:18:26 -05006118 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006119 cFYI(1, "EA list appears to go beyond SMB");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006120 rc = -EIO;
6121 goto QAllEAsOut;
6122 }
6123
Jeff Laytonf0d38682010-02-10 16:18:26 -05006124 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05006125 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006126 temp_fea = ea_response_data->list;
6127 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05006128 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00006129 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006130 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006131
Jeff Layton6e462b92010-02-10 16:18:26 -05006132 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006133 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006134 /* make sure we can read name_len and value_len */
6135 if (list_len < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006136 cFYI(1, "EA entry goes beyond length of list");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006137 rc = -EIO;
6138 goto QAllEAsOut;
6139 }
6140
6141 name_len = temp_fea->name_len;
6142 value_len = le16_to_cpu(temp_fea->value_len);
6143 list_len -= name_len + 1 + value_len;
6144 if (list_len < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006145 cFYI(1, "EA entry goes beyond length of list");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006146 rc = -EIO;
6147 goto QAllEAsOut;
6148 }
6149
Jeff Layton31c05192010-02-10 16:18:26 -05006150 if (ea_name) {
Jeff Layton91d065c2011-07-26 18:23:47 -04006151 if (ea_name_len == name_len &&
Jeff Laytonac423442011-10-11 06:41:32 -04006152 memcmp(ea_name, temp_ptr, name_len) == 0) {
Jeff Layton31c05192010-02-10 16:18:26 -05006153 temp_ptr += name_len + 1;
6154 rc = value_len;
6155 if (buf_size == 0)
6156 goto QAllEAsOut;
6157 if ((size_t)value_len > buf_size) {
6158 rc = -ERANGE;
6159 goto QAllEAsOut;
6160 }
6161 memcpy(EAData, temp_ptr, value_len);
6162 goto QAllEAsOut;
6163 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006164 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05006165 /* account for prefix user. and trailing null */
6166 rc += (5 + 1 + name_len);
6167 if (rc < (int) buf_size) {
6168 memcpy(EAData, "user.", 5);
6169 EAData += 5;
6170 memcpy(EAData, temp_ptr, name_len);
6171 EAData += name_len;
6172 /* null terminate name */
6173 *EAData = 0;
6174 ++EAData;
6175 } else if (buf_size == 0) {
6176 /* skip copy - calc size only */
6177 } else {
6178 /* stop before overrun buffer */
6179 rc = -ERANGE;
6180 break;
6181 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006182 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05006183 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006184 temp_fea = (struct fea *)temp_ptr;
6185 }
6186
Jeff Layton31c05192010-02-10 16:18:26 -05006187 /* didn't find the named attribute */
6188 if (ea_name)
6189 rc = -ENODATA;
6190
Jeff Laytonf0d38682010-02-10 16:18:26 -05006191QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00006192 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006193 if (rc == -EAGAIN)
6194 goto QAllEAsRetry;
6195
6196 return (ssize_t)rc;
6197}
6198
Linus Torvalds1da177e2005-04-16 15:20:36 -07006199int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006200CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
6201 const char *fileName, const char *ea_name, const void *ea_value,
Steve French50c2f752007-07-13 00:33:32 +00006202 const __u16 ea_value_len, const struct nls_table *nls_codepage,
6203 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006204{
6205 struct smb_com_transaction2_spi_req *pSMB = NULL;
6206 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
6207 struct fealist *parm_data;
6208 int name_len;
6209 int rc = 0;
6210 int bytes_returned = 0;
6211 __u16 params, param_offset, byte_count, offset, count;
6212
Joe Perchesb6b38f72010-04-21 03:50:45 +00006213 cFYI(1, "In SetEA");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006214SetEARetry:
6215 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6216 (void **) &pSMBr);
6217 if (rc)
6218 return rc;
6219
6220 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6221 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006222 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
6223 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006224 name_len++; /* trailing null */
6225 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00006226 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006227 name_len = strnlen(fileName, PATH_MAX);
6228 name_len++; /* trailing null */
6229 strncpy(pSMB->FileName, fileName, name_len);
6230 }
6231
6232 params = 6 + name_len;
6233
6234 /* done calculating parms using name_len of file name,
6235 now use name_len to calculate length of ea name
6236 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00006237 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006238 name_len = 0;
6239 else
Steve French50c2f752007-07-13 00:33:32 +00006240 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006241
Steve Frenchdae5dbdb2007-12-30 23:49:57 +00006242 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006243 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006244 /* BB find max SMB PDU from sess */
6245 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006246 pSMB->MaxSetupCount = 0;
6247 pSMB->Reserved = 0;
6248 pSMB->Flags = 0;
6249 pSMB->Timeout = 0;
6250 pSMB->Reserved2 = 0;
6251 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006252 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006253 offset = param_offset + params;
6254 pSMB->InformationLevel =
6255 cpu_to_le16(SMB_SET_FILE_EA);
6256
6257 parm_data =
6258 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
6259 offset);
6260 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6261 pSMB->DataOffset = cpu_to_le16(offset);
6262 pSMB->SetupCount = 1;
6263 pSMB->Reserved3 = 0;
6264 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6265 byte_count = 3 /* pad */ + params + count;
6266 pSMB->DataCount = cpu_to_le16(count);
6267 parm_data->list_len = cpu_to_le32(count);
6268 parm_data->list[0].EA_flags = 0;
6269 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08006270 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006271 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00006272 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00006273 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006274 parm_data->list[0].name[name_len] = 0;
6275 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
6276 /* caller ensures that ea_value_len is less than 64K but
6277 we need to ensure that it fits within the smb */
6278
Steve French50c2f752007-07-13 00:33:32 +00006279 /*BB add length check to see if it would fit in
6280 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00006281 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
6282 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00006283 memcpy(parm_data->list[0].name+name_len+1,
6284 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006285
6286 pSMB->TotalDataCount = pSMB->DataCount;
6287 pSMB->ParameterCount = cpu_to_le16(params);
6288 pSMB->TotalParameterCount = pSMB->ParameterCount;
6289 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006290 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006291 pSMB->ByteCount = cpu_to_le16(byte_count);
6292 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6293 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006294 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00006295 cFYI(1, "SetPathInfo (EA) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006296
6297 cifs_buf_release(pSMB);
6298
6299 if (rc == -EAGAIN)
6300 goto SetEARetry;
6301
6302 return rc;
6303}
Linus Torvalds1da177e2005-04-16 15:20:36 -07006304#endif
Steve French0eff0e22011-02-24 05:39:23 +00006305
6306#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */
6307/*
6308 * Years ago the kernel added a "dnotify" function for Samba server,
6309 * to allow network clients (such as Windows) to display updated
6310 * lists of files in directory listings automatically when
6311 * files are added by one user when another user has the
6312 * same directory open on their desktop. The Linux cifs kernel
6313 * client hooked into the kernel side of this interface for
6314 * the same reason, but ironically when the VFS moved from
6315 * "dnotify" to "inotify" it became harder to plug in Linux
6316 * network file system clients (the most obvious use case
6317 * for notify interfaces is when multiple users can update
6318 * the contents of the same directory - exactly what network
6319 * file systems can do) although the server (Samba) could
6320 * still use it. For the short term we leave the worker
6321 * function ifdeffed out (below) until inotify is fixed
6322 * in the VFS to make it easier to plug in network file
6323 * system clients. If inotify turns out to be permanently
6324 * incompatible for network fs clients, we could instead simply
6325 * expose this config flag by adding a future cifs (and smb2) notify ioctl.
6326 */
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006327int CIFSSMBNotify(const unsigned int xid, struct cifs_tcon *tcon,
Steve French0eff0e22011-02-24 05:39:23 +00006328 const int notify_subdirs, const __u16 netfid,
6329 __u32 filter, struct file *pfile, int multishot,
6330 const struct nls_table *nls_codepage)
6331{
6332 int rc = 0;
6333 struct smb_com_transaction_change_notify_req *pSMB = NULL;
6334 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
6335 struct dir_notify_req *dnotify_req;
6336 int bytes_returned;
6337
6338 cFYI(1, "In CIFSSMBNotify for file handle %d", (int)netfid);
6339 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
6340 (void **) &pSMBr);
6341 if (rc)
6342 return rc;
6343
6344 pSMB->TotalParameterCount = 0 ;
6345 pSMB->TotalDataCount = 0;
6346 pSMB->MaxParameterCount = cpu_to_le32(2);
Jeff Laytonc974bef2011-10-11 06:41:32 -04006347 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Steve French0eff0e22011-02-24 05:39:23 +00006348 pSMB->MaxSetupCount = 4;
6349 pSMB->Reserved = 0;
6350 pSMB->ParameterOffset = 0;
6351 pSMB->DataCount = 0;
6352 pSMB->DataOffset = 0;
6353 pSMB->SetupCount = 4; /* single byte does not need le conversion */
6354 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
6355 pSMB->ParameterCount = pSMB->TotalParameterCount;
6356 if (notify_subdirs)
6357 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
6358 pSMB->Reserved2 = 0;
6359 pSMB->CompletionFilter = cpu_to_le32(filter);
6360 pSMB->Fid = netfid; /* file handle always le */
6361 pSMB->ByteCount = 0;
6362
6363 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6364 (struct smb_hdr *)pSMBr, &bytes_returned,
6365 CIFS_ASYNC_OP);
6366 if (rc) {
6367 cFYI(1, "Error in Notify = %d", rc);
6368 } else {
6369 /* Add file to outstanding requests */
6370 /* BB change to kmem cache alloc */
6371 dnotify_req = kmalloc(
6372 sizeof(struct dir_notify_req),
6373 GFP_KERNEL);
6374 if (dnotify_req) {
6375 dnotify_req->Pid = pSMB->hdr.Pid;
6376 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
6377 dnotify_req->Mid = pSMB->hdr.Mid;
6378 dnotify_req->Tid = pSMB->hdr.Tid;
6379 dnotify_req->Uid = pSMB->hdr.Uid;
6380 dnotify_req->netfid = netfid;
6381 dnotify_req->pfile = pfile;
6382 dnotify_req->filter = filter;
6383 dnotify_req->multishot = multishot;
6384 spin_lock(&GlobalMid_Lock);
6385 list_add_tail(&dnotify_req->lhead,
6386 &GlobalDnotifyReqList);
6387 spin_unlock(&GlobalMid_Lock);
6388 } else
6389 rc = -ENOMEM;
6390 }
6391 cifs_buf_release(pSMB);
6392 return rc;
6393}
6394#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */