blob: eb3d2cf76e6e75bcf5ad32c30f15405540b43d3d [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 Layton99d86c8f2011-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,
Steve Frenchd6e906f2012-09-18 16:20:31 -07002927 const char *from_name, const char *to_name,
2928 struct cifs_sb_info *cifs_sb)
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;
Steve Frenchd6e906f2012-09-18 16:20:31 -07002936 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002937
Joe Perchesb6b38f72010-04-21 03:50:45 +00002938 cFYI(1, "In CIFSCreateHardLink");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002939winCreateHardLinkRetry:
2940
2941 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2942 (void **) &pSMBr);
2943 if (rc)
2944 return rc;
2945
2946 pSMB->SearchAttributes =
2947 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2948 ATTR_DIRECTORY);
2949 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2950 pSMB->ClusterCount = 0;
2951
2952 pSMB->BufferFormat = 0x04;
2953
2954 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2955 name_len =
Steve Frenchd6e906f2012-09-18 16:20:31 -07002956 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, from_name,
2957 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002958 name_len++; /* trailing null */
2959 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05002960
2961 /* protocol specifies ASCII buffer format (0x04) for unicode */
2962 pSMB->OldFileName[name_len] = 0x04;
2963 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002964 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002965 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Steve Frenchd6e906f2012-09-18 16:20:31 -07002966 to_name, PATH_MAX, cifs_sb->local_nls,
2967 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002968 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2969 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002970 } else { /* BB improve the check for buffer overruns BB */
Steve Frenchd6e906f2012-09-18 16:20:31 -07002971 name_len = strnlen(from_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002972 name_len++; /* trailing null */
Steve Frenchd6e906f2012-09-18 16:20:31 -07002973 strncpy(pSMB->OldFileName, from_name, name_len);
2974 name_len2 = strnlen(to_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002975 name_len2++; /* trailing null */
2976 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Steve Frenchd6e906f2012-09-18 16:20:31 -07002977 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002978 name_len2++; /* trailing null */
2979 name_len2++; /* signature byte */
2980 }
2981
2982 count = 1 /* string type byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002983 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002984 pSMB->ByteCount = cpu_to_le16(count);
2985
2986 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2987 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002988 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002989 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002990 cFYI(1, "Send error in hard link (NT rename) = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00002991
Linus Torvalds1da177e2005-04-16 15:20:36 -07002992 cifs_buf_release(pSMB);
2993 if (rc == -EAGAIN)
2994 goto winCreateHardLinkRetry;
2995
2996 return rc;
2997}
2998
2999int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003000CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04003001 const unsigned char *searchName, char **symlinkinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003002 const struct nls_table *nls_codepage)
3003{
3004/* SMB_QUERY_FILE_UNIX_LINK */
3005 TRANSACTION2_QPI_REQ *pSMB = NULL;
3006 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3007 int rc = 0;
3008 int bytes_returned;
3009 int name_len;
3010 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04003011 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003012
Joe Perchesb6b38f72010-04-21 03:50:45 +00003013 cFYI(1, "In QPathSymLinkInfo (Unix) for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003014
3015querySymLinkRetry:
3016 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3017 (void **) &pSMBr);
3018 if (rc)
3019 return rc;
3020
3021 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3022 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003023 cifs_strtoUTF16((__le16 *) pSMB->FileName, searchName,
3024 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003025 name_len++; /* trailing null */
3026 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003027 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003028 name_len = strnlen(searchName, PATH_MAX);
3029 name_len++; /* trailing null */
3030 strncpy(pSMB->FileName, searchName, name_len);
3031 }
3032
3033 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3034 pSMB->TotalDataCount = 0;
3035 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04003036 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003037 pSMB->MaxSetupCount = 0;
3038 pSMB->Reserved = 0;
3039 pSMB->Flags = 0;
3040 pSMB->Timeout = 0;
3041 pSMB->Reserved2 = 0;
3042 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003043 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003044 pSMB->DataCount = 0;
3045 pSMB->DataOffset = 0;
3046 pSMB->SetupCount = 1;
3047 pSMB->Reserved3 = 0;
3048 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3049 byte_count = params + 1 /* pad */ ;
3050 pSMB->TotalParameterCount = cpu_to_le16(params);
3051 pSMB->ParameterCount = pSMB->TotalParameterCount;
3052 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
3053 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003054 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003055 pSMB->ByteCount = cpu_to_le16(byte_count);
3056
3057 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3058 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3059 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003060 cFYI(1, "Send error in QuerySymLinkInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003061 } else {
3062 /* decode response */
3063
3064 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003065 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003066 if (rc || get_bcc(&pSMBr->hdr) < 2)
Jeff Layton460b9692009-04-30 07:17:56 -04003067 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003068 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00003069 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04003070 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003071
Jeff Layton460b9692009-04-30 07:17:56 -04003072 data_start = ((char *) &pSMBr->hdr.Protocol) +
3073 le16_to_cpu(pSMBr->t2.DataOffset);
3074
Steve French0e0d2cf2009-05-01 05:27:32 +00003075 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3076 is_unicode = true;
3077 else
3078 is_unicode = false;
3079
Steve French737b7582005-04-28 22:41:06 -07003080 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchacbbb762012-01-18 22:32:33 -06003081 *symlinkinfo = cifs_strndup_from_utf16(data_start,
3082 count, is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04003083 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04003084 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003085 }
3086 }
3087 cifs_buf_release(pSMB);
3088 if (rc == -EAGAIN)
3089 goto querySymLinkRetry;
3090 return rc;
3091}
3092
Steve Frenchc52a95542011-02-24 06:16:22 +00003093#ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL
3094/*
3095 * Recent Windows versions now create symlinks more frequently
3096 * and they use the "reparse point" mechanism below. We can of course
3097 * do symlinks nicely to Samba and other servers which support the
3098 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
3099 * "MF" symlinks optionally, but for recent Windows we really need to
3100 * reenable the code below and fix the cifs_symlink callers to handle this.
3101 * In the interim this code has been moved to its own config option so
3102 * it is not compiled in by default until callers fixed up and more tested.
3103 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003104int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003105CIFSSMBQueryReparseLinkInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003106 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00003107 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003108 const struct nls_table *nls_codepage)
3109{
3110 int rc = 0;
3111 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00003112 struct smb_com_transaction_ioctl_req *pSMB;
3113 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003114
Joe Perchesb6b38f72010-04-21 03:50:45 +00003115 cFYI(1, "In Windows reparse style QueryLink for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003116 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3117 (void **) &pSMBr);
3118 if (rc)
3119 return rc;
3120
3121 pSMB->TotalParameterCount = 0 ;
3122 pSMB->TotalDataCount = 0;
3123 pSMB->MaxParameterCount = cpu_to_le32(2);
3124 /* BB find exact data count max from sess structure BB */
Jeff Laytonc974bef2011-10-11 06:41:32 -04003125 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003126 pSMB->MaxSetupCount = 4;
3127 pSMB->Reserved = 0;
3128 pSMB->ParameterOffset = 0;
3129 pSMB->DataCount = 0;
3130 pSMB->DataOffset = 0;
3131 pSMB->SetupCount = 4;
3132 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
3133 pSMB->ParameterCount = pSMB->TotalParameterCount;
3134 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
3135 pSMB->IsFsctl = 1; /* FSCTL */
3136 pSMB->IsRootFlag = 0;
3137 pSMB->Fid = fid; /* file handle always le */
3138 pSMB->ByteCount = 0;
3139
3140 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3141 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3142 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003143 cFYI(1, "Send error in QueryReparseLinkInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003144 } else { /* decode response */
3145 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
3146 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
Jeff Layton820a8032011-05-04 08:05:26 -04003147 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
3148 /* BB also check enough total bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003149 rc = -EIO; /* bad smb */
Steve Frenchafe48c32009-05-02 05:25:46 +00003150 goto qreparse_out;
3151 }
3152 if (data_count && (data_count < 2048)) {
3153 char *end_of_smb = 2 /* sizeof byte count */ +
Jeff Layton820a8032011-05-04 08:05:26 -04003154 get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003155
Steve Frenchafe48c32009-05-02 05:25:46 +00003156 struct reparse_data *reparse_buf =
Steve French50c2f752007-07-13 00:33:32 +00003157 (struct reparse_data *)
3158 ((char *)&pSMBr->hdr.Protocol
3159 + data_offset);
Steve Frenchafe48c32009-05-02 05:25:46 +00003160 if ((char *)reparse_buf >= end_of_smb) {
3161 rc = -EIO;
3162 goto qreparse_out;
3163 }
3164 if ((reparse_buf->LinkNamesBuf +
3165 reparse_buf->TargetNameOffset +
3166 reparse_buf->TargetNameLen) > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003167 cFYI(1, "reparse buf beyond SMB");
Steve Frenchafe48c32009-05-02 05:25:46 +00003168 rc = -EIO;
3169 goto qreparse_out;
3170 }
Steve French50c2f752007-07-13 00:33:32 +00003171
Steve Frenchafe48c32009-05-02 05:25:46 +00003172 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3173 cifs_from_ucs2(symlinkinfo, (__le16 *)
Steve French50c2f752007-07-13 00:33:32 +00003174 (reparse_buf->LinkNamesBuf +
3175 reparse_buf->TargetNameOffset),
Steve Frenchafe48c32009-05-02 05:25:46 +00003176 buflen,
3177 reparse_buf->TargetNameLen,
3178 nls_codepage, 0);
3179 } else { /* ASCII names */
3180 strncpy(symlinkinfo,
3181 reparse_buf->LinkNamesBuf +
3182 reparse_buf->TargetNameOffset,
3183 min_t(const int, buflen,
3184 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003185 }
Steve Frenchafe48c32009-05-02 05:25:46 +00003186 } else {
3187 rc = -EIO;
Joe Perchesb6b38f72010-04-21 03:50:45 +00003188 cFYI(1, "Invalid return data count on "
3189 "get reparse info ioctl");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003190 }
Steve Frenchafe48c32009-05-02 05:25:46 +00003191 symlinkinfo[buflen] = 0; /* just in case so the caller
3192 does not go off the end of the buffer */
Joe Perchesb6b38f72010-04-21 03:50:45 +00003193 cFYI(1, "readlink result - %s", symlinkinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003194 }
Steve French989c7e52009-05-02 05:32:20 +00003195
Linus Torvalds1da177e2005-04-16 15:20:36 -07003196qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07003197 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003198
3199 /* Note: On -EAGAIN error only caller can retry on handle based calls
3200 since file handle passed in no longer valid */
3201
3202 return rc;
3203}
Steve Frenchc52a95542011-02-24 06:16:22 +00003204#endif /* CIFS_SYMLINK_EXPERIMENTAL */ /* BB temporarily unused */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003205
3206#ifdef CONFIG_CIFS_POSIX
3207
3208/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00003209static void cifs_convert_ace(posix_acl_xattr_entry *ace,
3210 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003211{
3212 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08003213 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
3214 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
3215 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesb6b38f72010-04-21 03:50:45 +00003216 /* cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003217
3218 return;
3219}
3220
3221/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00003222static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
3223 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003224{
3225 int size = 0;
3226 int i;
3227 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00003228 struct cifs_posix_ace *pACE;
3229 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
3230 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003231
3232 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
3233 return -EOPNOTSUPP;
3234
Steve French790fe572007-07-07 19:25:05 +00003235 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003236 count = le16_to_cpu(cifs_acl->access_entry_count);
3237 pACE = &cifs_acl->ace_array[0];
3238 size = sizeof(struct cifs_posix_acl);
3239 size += sizeof(struct cifs_posix_ace) * count;
3240 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003241 if (size_of_data_area < size) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003242 cFYI(1, "bad CIFS POSIX ACL size %d vs. %d",
3243 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003244 return -EINVAL;
3245 }
Steve French790fe572007-07-07 19:25:05 +00003246 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003247 count = le16_to_cpu(cifs_acl->access_entry_count);
3248 size = sizeof(struct cifs_posix_acl);
3249 size += sizeof(struct cifs_posix_ace) * count;
3250/* skip past access ACEs to get to default ACEs */
3251 pACE = &cifs_acl->ace_array[count];
3252 count = le16_to_cpu(cifs_acl->default_entry_count);
3253 size += sizeof(struct cifs_posix_ace) * count;
3254 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003255 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003256 return -EINVAL;
3257 } else {
3258 /* illegal type */
3259 return -EINVAL;
3260 }
3261
3262 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00003263 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00003264 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00003265 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003266 return -ERANGE;
3267 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08003268 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00003269 for (i = 0; i < count ; i++) {
3270 cifs_convert_ace(&local_acl->a_entries[i], pACE);
3271 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003272 }
3273 }
3274 return size;
3275}
3276
Steve French50c2f752007-07-13 00:33:32 +00003277static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
3278 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003279{
3280 __u16 rc = 0; /* 0 = ACL converted ok */
3281
Steve Frenchff7feac2005-11-15 16:45:16 -08003282 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
3283 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003284 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00003285 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003286 /* Probably no need to le convert -1 on any arch but can not hurt */
3287 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00003288 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08003289 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesb6b38f72010-04-21 03:50:45 +00003290 /*cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id);*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003291 return rc;
3292}
3293
3294/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00003295static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
3296 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003297{
3298 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00003299 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
3300 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003301 int count;
3302 int i;
3303
Steve French790fe572007-07-07 19:25:05 +00003304 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003305 return 0;
3306
3307 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesb6b38f72010-04-21 03:50:45 +00003308 cFYI(1, "setting acl with %d entries from buf of length %d and "
Steve French63135e02007-07-17 17:34:02 +00003309 "version of %d",
Joe Perchesb6b38f72010-04-21 03:50:45 +00003310 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00003311 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003312 cFYI(1, "unknown POSIX ACL version %d",
3313 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003314 return 0;
3315 }
3316 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00003317 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08003318 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00003319 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08003320 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003321 else {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003322 cFYI(1, "unknown ACL type %d", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003323 return 0;
3324 }
Steve French50c2f752007-07-13 00:33:32 +00003325 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003326 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
3327 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00003328 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003329 /* ACE not converted */
3330 break;
3331 }
3332 }
Steve French790fe572007-07-07 19:25:05 +00003333 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003334 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
3335 rc += sizeof(struct cifs_posix_acl);
3336 /* BB add check to make sure ACL does not overflow SMB */
3337 }
3338 return rc;
3339}
3340
3341int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003342CIFSSMBGetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003343 const unsigned char *searchName,
3344 char *acl_inf, const int buflen, const int acl_type,
3345 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003346{
3347/* SMB_QUERY_POSIX_ACL */
3348 TRANSACTION2_QPI_REQ *pSMB = NULL;
3349 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3350 int rc = 0;
3351 int bytes_returned;
3352 int name_len;
3353 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00003354
Joe Perchesb6b38f72010-04-21 03:50:45 +00003355 cFYI(1, "In GetPosixACL (Unix) for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003356
3357queryAclRetry:
3358 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3359 (void **) &pSMBr);
3360 if (rc)
3361 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003362
Linus Torvalds1da177e2005-04-16 15:20:36 -07003363 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3364 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003365 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3366 searchName, PATH_MAX, nls_codepage,
3367 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003368 name_len++; /* trailing null */
3369 name_len *= 2;
3370 pSMB->FileName[name_len] = 0;
3371 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00003372 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003373 name_len = strnlen(searchName, PATH_MAX);
3374 name_len++; /* trailing null */
3375 strncpy(pSMB->FileName, searchName, name_len);
3376 }
3377
3378 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3379 pSMB->TotalDataCount = 0;
3380 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00003381 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003382 pSMB->MaxDataCount = cpu_to_le16(4000);
3383 pSMB->MaxSetupCount = 0;
3384 pSMB->Reserved = 0;
3385 pSMB->Flags = 0;
3386 pSMB->Timeout = 0;
3387 pSMB->Reserved2 = 0;
3388 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003389 offsetof(struct smb_com_transaction2_qpi_req,
3390 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003391 pSMB->DataCount = 0;
3392 pSMB->DataOffset = 0;
3393 pSMB->SetupCount = 1;
3394 pSMB->Reserved3 = 0;
3395 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3396 byte_count = params + 1 /* pad */ ;
3397 pSMB->TotalParameterCount = cpu_to_le16(params);
3398 pSMB->ParameterCount = pSMB->TotalParameterCount;
3399 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
3400 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003401 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003402 pSMB->ByteCount = cpu_to_le16(byte_count);
3403
3404 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3405 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003406 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003407 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003408 cFYI(1, "Send error in Query POSIX ACL = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003409 } else {
3410 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00003411
Linus Torvalds1da177e2005-04-16 15:20:36 -07003412 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003413 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003414 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003415 rc = -EIO; /* bad smb */
3416 else {
3417 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3418 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3419 rc = cifs_copy_posix_acl(acl_inf,
3420 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00003421 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003422 }
3423 }
3424 cifs_buf_release(pSMB);
3425 if (rc == -EAGAIN)
3426 goto queryAclRetry;
3427 return rc;
3428}
3429
3430int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003431CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003432 const unsigned char *fileName,
3433 const char *local_acl, const int buflen,
3434 const int acl_type,
3435 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003436{
3437 struct smb_com_transaction2_spi_req *pSMB = NULL;
3438 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3439 char *parm_data;
3440 int name_len;
3441 int rc = 0;
3442 int bytes_returned = 0;
3443 __u16 params, byte_count, data_count, param_offset, offset;
3444
Joe Perchesb6b38f72010-04-21 03:50:45 +00003445 cFYI(1, "In SetPosixACL (Unix) for path %s", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003446setAclRetry:
3447 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003448 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003449 if (rc)
3450 return rc;
3451 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3452 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003453 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
3454 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003455 name_len++; /* trailing null */
3456 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003457 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003458 name_len = strnlen(fileName, PATH_MAX);
3459 name_len++; /* trailing null */
3460 strncpy(pSMB->FileName, fileName, name_len);
3461 }
3462 params = 6 + name_len;
3463 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003464 /* BB find max SMB size from sess */
3465 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003466 pSMB->MaxSetupCount = 0;
3467 pSMB->Reserved = 0;
3468 pSMB->Flags = 0;
3469 pSMB->Timeout = 0;
3470 pSMB->Reserved2 = 0;
3471 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003472 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003473 offset = param_offset + params;
3474 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
3475 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3476
3477 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00003478 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003479
Steve French790fe572007-07-07 19:25:05 +00003480 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003481 rc = -EOPNOTSUPP;
3482 goto setACLerrorExit;
3483 }
3484 pSMB->DataOffset = cpu_to_le16(offset);
3485 pSMB->SetupCount = 1;
3486 pSMB->Reserved3 = 0;
3487 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3488 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
3489 byte_count = 3 /* pad */ + params + data_count;
3490 pSMB->DataCount = cpu_to_le16(data_count);
3491 pSMB->TotalDataCount = pSMB->DataCount;
3492 pSMB->ParameterCount = cpu_to_le16(params);
3493 pSMB->TotalParameterCount = pSMB->ParameterCount;
3494 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003495 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003496 pSMB->ByteCount = cpu_to_le16(byte_count);
3497 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003498 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003499 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003500 cFYI(1, "Set POSIX ACL returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003501
3502setACLerrorExit:
3503 cifs_buf_release(pSMB);
3504 if (rc == -EAGAIN)
3505 goto setAclRetry;
3506 return rc;
3507}
3508
Steve Frenchf654bac2005-04-28 22:41:04 -07003509/* BB fix tabs in this function FIXME BB */
3510int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003511CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00003512 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07003513{
Steve French50c2f752007-07-13 00:33:32 +00003514 int rc = 0;
3515 struct smb_t2_qfi_req *pSMB = NULL;
3516 struct smb_t2_qfi_rsp *pSMBr = NULL;
3517 int bytes_returned;
3518 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07003519
Joe Perchesb6b38f72010-04-21 03:50:45 +00003520 cFYI(1, "In GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00003521 if (tcon == NULL)
3522 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07003523
3524GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003525 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3526 (void **) &pSMBr);
3527 if (rc)
3528 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003529
Steve Frenchad7a2922008-02-07 23:25:02 +00003530 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003531 pSMB->t2.TotalDataCount = 0;
3532 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3533 /* BB find exact max data count below from sess structure BB */
3534 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3535 pSMB->t2.MaxSetupCount = 0;
3536 pSMB->t2.Reserved = 0;
3537 pSMB->t2.Flags = 0;
3538 pSMB->t2.Timeout = 0;
3539 pSMB->t2.Reserved2 = 0;
3540 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3541 Fid) - 4);
3542 pSMB->t2.DataCount = 0;
3543 pSMB->t2.DataOffset = 0;
3544 pSMB->t2.SetupCount = 1;
3545 pSMB->t2.Reserved3 = 0;
3546 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3547 byte_count = params + 1 /* pad */ ;
3548 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3549 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3550 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3551 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003552 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003553 inc_rfc1001_len(pSMB, byte_count);
Steve French790fe572007-07-07 19:25:05 +00003554 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003555
Steve French790fe572007-07-07 19:25:05 +00003556 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3557 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3558 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003559 cFYI(1, "error %d in GetExtAttr", rc);
Steve French790fe572007-07-07 19:25:05 +00003560 } else {
3561 /* decode response */
3562 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003563 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003564 if (rc || get_bcc(&pSMBr->hdr) < 2)
Steve French790fe572007-07-07 19:25:05 +00003565 /* If rc should we check for EOPNOSUPP and
3566 disable the srvino flag? or in caller? */
3567 rc = -EIO; /* bad smb */
3568 else {
3569 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3570 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3571 struct file_chattr_info *pfinfo;
3572 /* BB Do we need a cast or hash here ? */
3573 if (count != 16) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003574 cFYI(1, "Illegal size ret in GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00003575 rc = -EIO;
3576 goto GetExtAttrOut;
3577 }
3578 pfinfo = (struct file_chattr_info *)
3579 (data_offset + (char *) &pSMBr->hdr.Protocol);
3580 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003581 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003582 }
3583 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003584GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003585 cifs_buf_release(pSMB);
3586 if (rc == -EAGAIN)
3587 goto GetExtAttrRetry;
3588 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003589}
3590
Steve Frenchf654bac2005-04-28 22:41:04 -07003591#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003592
Jeff Layton79df1ba2010-12-06 12:52:08 -05003593#ifdef CONFIG_CIFS_ACL
3594/*
3595 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3596 * all NT TRANSACTS that we init here have total parm and data under about 400
3597 * bytes (to fit in small cifs buffer size), which is the case so far, it
3598 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3599 * returned setup area) and MaxParameterCount (returned parms size) must be set
3600 * by caller
3601 */
3602static int
3603smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French96daf2b2011-05-27 04:34:02 +00003604 const int parm_len, struct cifs_tcon *tcon,
Jeff Layton79df1ba2010-12-06 12:52:08 -05003605 void **ret_buf)
3606{
3607 int rc;
3608 __u32 temp_offset;
3609 struct smb_com_ntransact_req *pSMB;
3610
3611 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3612 (void **)&pSMB);
3613 if (rc)
3614 return rc;
3615 *ret_buf = (void *)pSMB;
3616 pSMB->Reserved = 0;
3617 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3618 pSMB->TotalDataCount = 0;
Jeff Laytonc974bef2011-10-11 06:41:32 -04003619 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003620 pSMB->ParameterCount = pSMB->TotalParameterCount;
3621 pSMB->DataCount = pSMB->TotalDataCount;
3622 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3623 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3624 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3625 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3626 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3627 pSMB->SubCommand = cpu_to_le16(sub_command);
3628 return 0;
3629}
3630
3631static int
3632validate_ntransact(char *buf, char **ppparm, char **ppdata,
3633 __u32 *pparmlen, __u32 *pdatalen)
3634{
3635 char *end_of_smb;
3636 __u32 data_count, data_offset, parm_count, parm_offset;
3637 struct smb_com_ntransact_rsp *pSMBr;
Jeff Layton820a8032011-05-04 08:05:26 -04003638 u16 bcc;
Jeff Layton79df1ba2010-12-06 12:52:08 -05003639
3640 *pdatalen = 0;
3641 *pparmlen = 0;
3642
3643 if (buf == NULL)
3644 return -EINVAL;
3645
3646 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3647
Jeff Layton820a8032011-05-04 08:05:26 -04003648 bcc = get_bcc(&pSMBr->hdr);
3649 end_of_smb = 2 /* sizeof byte count */ + bcc +
Jeff Layton79df1ba2010-12-06 12:52:08 -05003650 (char *)&pSMBr->ByteCount;
3651
3652 data_offset = le32_to_cpu(pSMBr->DataOffset);
3653 data_count = le32_to_cpu(pSMBr->DataCount);
3654 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3655 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3656
3657 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3658 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3659
3660 /* should we also check that parm and data areas do not overlap? */
3661 if (*ppparm > end_of_smb) {
3662 cFYI(1, "parms start after end of smb");
3663 return -EINVAL;
3664 } else if (parm_count + *ppparm > end_of_smb) {
3665 cFYI(1, "parm end after end of smb");
3666 return -EINVAL;
3667 } else if (*ppdata > end_of_smb) {
3668 cFYI(1, "data starts after end of smb");
3669 return -EINVAL;
3670 } else if (data_count + *ppdata > end_of_smb) {
3671 cFYI(1, "data %p + count %d (%p) past smb end %p start %p",
3672 *ppdata, data_count, (data_count + *ppdata),
3673 end_of_smb, pSMBr);
3674 return -EINVAL;
Jeff Layton820a8032011-05-04 08:05:26 -04003675 } else if (parm_count + data_count > bcc) {
Jeff Layton79df1ba2010-12-06 12:52:08 -05003676 cFYI(1, "parm count and data count larger than SMB");
3677 return -EINVAL;
3678 }
3679 *pdatalen = data_count;
3680 *pparmlen = parm_count;
3681 return 0;
3682}
3683
Steve French0a4b92c2006-01-12 15:44:21 -08003684/* Get Security Descriptor (by handle) from remote server for a file or dir */
3685int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003686CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003687 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003688{
3689 int rc = 0;
3690 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003691 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003692 struct kvec iov[1];
3693
Joe Perchesb6b38f72010-04-21 03:50:45 +00003694 cFYI(1, "GetCifsACL");
Steve French0a4b92c2006-01-12 15:44:21 -08003695
Steve French630f3f0c2007-10-25 21:17:17 +00003696 *pbuflen = 0;
3697 *acl_inf = NULL;
3698
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003699 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003700 8 /* parm len */, tcon, (void **) &pSMB);
3701 if (rc)
3702 return rc;
3703
3704 pSMB->MaxParameterCount = cpu_to_le32(4);
3705 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3706 pSMB->MaxSetupCount = 0;
3707 pSMB->Fid = fid; /* file handle always le */
3708 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3709 CIFS_ACL_DACL);
3710 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003711 inc_rfc1001_len(pSMB, 11);
Steve French0a4b92c2006-01-12 15:44:21 -08003712 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003713 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French0a4b92c2006-01-12 15:44:21 -08003714
Steve Frencha761ac52007-10-18 21:45:27 +00003715 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Jeff Layton77499812011-01-11 07:24:23 -05003716 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003717 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Steve French0a4b92c2006-01-12 15:44:21 -08003718 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003719 cFYI(1, "Send error in QuerySecDesc = %d", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08003720 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003721 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003722 __u32 parm_len;
3723 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003724 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003725 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003726
3727/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003728 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003729 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003730 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003731 goto qsec_out;
3732 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3733
Joe Perchesb6b38f72010-04-21 03:50:45 +00003734 cFYI(1, "smb %p parm %p data %p", pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08003735
3736 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3737 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003738 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003739 goto qsec_out;
3740 }
3741
3742/* BB check that data area is minimum length and as big as acl_len */
3743
Steve Frenchaf6f4612007-10-16 18:40:37 +00003744 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003745 if (acl_len != *pbuflen) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003746 cERROR(1, "acl length %d does not match %d",
3747 acl_len, *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003748 if (*pbuflen > acl_len)
3749 *pbuflen = acl_len;
3750 }
Steve French0a4b92c2006-01-12 15:44:21 -08003751
Steve French630f3f0c2007-10-25 21:17:17 +00003752 /* check if buffer is big enough for the acl
3753 header followed by the smallest SID */
3754 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3755 (*pbuflen >= 64 * 1024)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003756 cERROR(1, "bad acl length %d", *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003757 rc = -EINVAL;
3758 *pbuflen = 0;
3759 } else {
3760 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3761 if (*acl_inf == NULL) {
3762 *pbuflen = 0;
3763 rc = -ENOMEM;
3764 }
3765 memcpy(*acl_inf, pdata, *pbuflen);
3766 }
Steve French0a4b92c2006-01-12 15:44:21 -08003767 }
3768qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003769 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003770 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003771 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003772 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003773/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003774 return rc;
3775}
Steve French97837582007-12-31 07:47:21 +00003776
3777int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003778CIFSSMBSetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003779 struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
Steve French97837582007-12-31 07:47:21 +00003780{
3781 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3782 int rc = 0;
3783 int bytes_returned = 0;
3784 SET_SEC_DESC_REQ *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003785 void *pSMBr;
Steve French97837582007-12-31 07:47:21 +00003786
3787setCifsAclRetry:
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003788 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, &pSMBr);
Steve French97837582007-12-31 07:47:21 +00003789 if (rc)
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003790 return rc;
Steve French97837582007-12-31 07:47:21 +00003791
3792 pSMB->MaxSetupCount = 0;
3793 pSMB->Reserved = 0;
3794
3795 param_count = 8;
3796 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3797 data_count = acllen;
3798 data_offset = param_offset + param_count;
3799 byte_count = 3 /* pad */ + param_count;
3800
3801 pSMB->DataCount = cpu_to_le32(data_count);
3802 pSMB->TotalDataCount = pSMB->DataCount;
3803 pSMB->MaxParameterCount = cpu_to_le32(4);
3804 pSMB->MaxDataCount = cpu_to_le32(16384);
3805 pSMB->ParameterCount = cpu_to_le32(param_count);
3806 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3807 pSMB->TotalParameterCount = pSMB->ParameterCount;
3808 pSMB->DataOffset = cpu_to_le32(data_offset);
3809 pSMB->SetupCount = 0;
3810 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3811 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3812
3813 pSMB->Fid = fid; /* file handle always le */
3814 pSMB->Reserved2 = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003815 pSMB->AclFlags = cpu_to_le32(aclflag);
Steve French97837582007-12-31 07:47:21 +00003816
3817 if (pntsd && acllen) {
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003818 memcpy((char *)pSMBr + offsetof(struct smb_hdr, Protocol) +
3819 data_offset, pntsd, acllen);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003820 inc_rfc1001_len(pSMB, byte_count + data_count);
Steve French97837582007-12-31 07:47:21 +00003821 } else
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003822 inc_rfc1001_len(pSMB, byte_count);
Steve French97837582007-12-31 07:47:21 +00003823
3824 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3825 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3826
Joe Perchesb6b38f72010-04-21 03:50:45 +00003827 cFYI(1, "SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00003828 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003829 cFYI(1, "Set CIFS ACL returned %d", rc);
Steve French97837582007-12-31 07:47:21 +00003830 cifs_buf_release(pSMB);
3831
3832 if (rc == -EAGAIN)
3833 goto setCifsAclRetry;
3834
3835 return (rc);
3836}
3837
Jeff Layton79df1ba2010-12-06 12:52:08 -05003838#endif /* CONFIG_CIFS_ACL */
Steve French0a4b92c2006-01-12 15:44:21 -08003839
Steve French6b8edfe2005-08-23 20:26:03 -07003840/* Legacy Query Path Information call for lookup to old servers such
3841 as Win9x/WinME */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003842int
3843SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon,
3844 const char *search_name, FILE_ALL_INFO *data,
3845 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003846{
Steve Frenchad7a2922008-02-07 23:25:02 +00003847 QUERY_INFORMATION_REQ *pSMB;
3848 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003849 int rc = 0;
3850 int bytes_returned;
3851 int name_len;
3852
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003853 cFYI(1, "In SMBQPath path %s", search_name);
Steve French6b8edfe2005-08-23 20:26:03 -07003854QInfRetry:
3855 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003856 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003857 if (rc)
3858 return rc;
3859
3860 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3861 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003862 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003863 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06003864 remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003865 name_len++; /* trailing null */
3866 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003867 } else {
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003868 name_len = strnlen(search_name, PATH_MAX);
Steve French6b8edfe2005-08-23 20:26:03 -07003869 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003870 strncpy(pSMB->FileName, search_name, name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07003871 }
3872 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003873 name_len++; /* account for buffer type byte */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003874 inc_rfc1001_len(pSMB, (__u16)name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07003875 pSMB->ByteCount = cpu_to_le16(name_len);
3876
3877 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003878 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003879 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003880 cFYI(1, "Send error in QueryInfo = %d", rc);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003881 } else if (data) {
Steve French1bd5bbc2006-09-28 03:35:57 +00003882 struct timespec ts;
3883 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00003884
3885 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003886 /* BB FIXME - add time zone adjustment BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003887 memset(data, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003888 ts.tv_nsec = 0;
3889 ts.tv_sec = time;
3890 /* decode time fields */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003891 data->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
3892 data->LastWriteTime = data->ChangeTime;
3893 data->LastAccessTime = 0;
3894 data->AllocationSize =
Steve French70ca7342005-09-22 16:32:06 -07003895 cpu_to_le64(le32_to_cpu(pSMBr->size));
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003896 data->EndOfFile = data->AllocationSize;
3897 data->Attributes =
Steve French70ca7342005-09-22 16:32:06 -07003898 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003899 } else
3900 rc = -EIO; /* bad buffer passed in */
3901
3902 cifs_buf_release(pSMB);
3903
3904 if (rc == -EAGAIN)
3905 goto QInfRetry;
3906
3907 return rc;
3908}
3909
Jeff Laytonbcd53572010-02-12 07:44:16 -05003910int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003911CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonbcd53572010-02-12 07:44:16 -05003912 u16 netfid, FILE_ALL_INFO *pFindData)
3913{
3914 struct smb_t2_qfi_req *pSMB = NULL;
3915 struct smb_t2_qfi_rsp *pSMBr = NULL;
3916 int rc = 0;
3917 int bytes_returned;
3918 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07003919
Jeff Laytonbcd53572010-02-12 07:44:16 -05003920QFileInfoRetry:
3921 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3922 (void **) &pSMBr);
3923 if (rc)
3924 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07003925
Jeff Laytonbcd53572010-02-12 07:44:16 -05003926 params = 2 /* level */ + 2 /* fid */;
3927 pSMB->t2.TotalDataCount = 0;
3928 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3929 /* BB find exact max data count below from sess structure BB */
3930 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3931 pSMB->t2.MaxSetupCount = 0;
3932 pSMB->t2.Reserved = 0;
3933 pSMB->t2.Flags = 0;
3934 pSMB->t2.Timeout = 0;
3935 pSMB->t2.Reserved2 = 0;
3936 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3937 Fid) - 4);
3938 pSMB->t2.DataCount = 0;
3939 pSMB->t2.DataOffset = 0;
3940 pSMB->t2.SetupCount = 1;
3941 pSMB->t2.Reserved3 = 0;
3942 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3943 byte_count = params + 1 /* pad */ ;
3944 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3945 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3946 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3947 pSMB->Pad = 0;
3948 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003949 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003950
3951 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3952 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3953 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00003954 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003955 } else { /* decode response */
3956 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3957
3958 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3959 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04003960 else if (get_bcc(&pSMBr->hdr) < 40)
Jeff Laytonbcd53572010-02-12 07:44:16 -05003961 rc = -EIO; /* bad smb */
3962 else if (pFindData) {
3963 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3964 memcpy((char *) pFindData,
3965 (char *) &pSMBr->hdr.Protocol +
3966 data_offset, sizeof(FILE_ALL_INFO));
3967 } else
3968 rc = -ENOMEM;
3969 }
3970 cifs_buf_release(pSMB);
3971 if (rc == -EAGAIN)
3972 goto QFileInfoRetry;
3973
3974 return rc;
3975}
Steve French6b8edfe2005-08-23 20:26:03 -07003976
Linus Torvalds1da177e2005-04-16 15:20:36 -07003977int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003978CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003979 const char *search_name, FILE_ALL_INFO *data,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003980 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003981 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003982{
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003983 /* level 263 SMB_QUERY_FILE_ALL_INFO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003984 TRANSACTION2_QPI_REQ *pSMB = NULL;
3985 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3986 int rc = 0;
3987 int bytes_returned;
3988 int name_len;
3989 __u16 params, byte_count;
3990
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003991 /* cFYI(1, "In QPathInfo path %s", search_name); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003992QPathInfoRetry:
3993 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3994 (void **) &pSMBr);
3995 if (rc)
3996 return rc;
3997
3998 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3999 name_len =
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004000 cifsConvertToUTF16((__le16 *) pSMB->FileName, search_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06004001 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004002 name_len++; /* trailing null */
4003 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004004 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004005 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004006 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004007 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004008 }
4009
Steve French50c2f752007-07-13 00:33:32 +00004010 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004011 pSMB->TotalDataCount = 0;
4012 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004013 /* BB find exact max SMB PDU from sess structure BB */
4014 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004015 pSMB->MaxSetupCount = 0;
4016 pSMB->Reserved = 0;
4017 pSMB->Flags = 0;
4018 pSMB->Timeout = 0;
4019 pSMB->Reserved2 = 0;
4020 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004021 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004022 pSMB->DataCount = 0;
4023 pSMB->DataOffset = 0;
4024 pSMB->SetupCount = 1;
4025 pSMB->Reserved3 = 0;
4026 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4027 byte_count = params + 1 /* pad */ ;
4028 pSMB->TotalParameterCount = cpu_to_le16(params);
4029 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00004030 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004031 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
4032 else
4033 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004034 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004035 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004036 pSMB->ByteCount = cpu_to_le16(byte_count);
4037
4038 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4039 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4040 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004041 cFYI(1, "Send error in QPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004042 } else { /* decode response */
4043 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4044
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004045 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4046 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004047 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004048 rc = -EIO; /* bad smb */
Jeff Layton820a8032011-05-04 08:05:26 -04004049 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
Steve French50c2f752007-07-13 00:33:32 +00004050 rc = -EIO; /* 24 or 26 expected but we do not read
4051 last field */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004052 else if (data) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004053 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004054 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00004055
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004056 /*
4057 * On legacy responses we do not read the last field,
4058 * EAsize, fortunately since it varies by subdialect and
4059 * also note it differs on Set vs Get, ie two bytes or 4
4060 * bytes depending but we don't care here.
4061 */
Steve Frenchad7a2922008-02-07 23:25:02 +00004062 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004063 size = sizeof(FILE_INFO_STANDARD);
4064 else
4065 size = sizeof(FILE_ALL_INFO);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004066 memcpy((char *) data, (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004067 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004068 } else
4069 rc = -ENOMEM;
4070 }
4071 cifs_buf_release(pSMB);
4072 if (rc == -EAGAIN)
4073 goto QPathInfoRetry;
4074
4075 return rc;
4076}
4077
4078int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004079CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004080 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
4081{
4082 struct smb_t2_qfi_req *pSMB = NULL;
4083 struct smb_t2_qfi_rsp *pSMBr = NULL;
4084 int rc = 0;
4085 int bytes_returned;
4086 __u16 params, byte_count;
4087
4088UnixQFileInfoRetry:
4089 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4090 (void **) &pSMBr);
4091 if (rc)
4092 return rc;
4093
4094 params = 2 /* level */ + 2 /* fid */;
4095 pSMB->t2.TotalDataCount = 0;
4096 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4097 /* BB find exact max data count below from sess structure BB */
4098 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4099 pSMB->t2.MaxSetupCount = 0;
4100 pSMB->t2.Reserved = 0;
4101 pSMB->t2.Flags = 0;
4102 pSMB->t2.Timeout = 0;
4103 pSMB->t2.Reserved2 = 0;
4104 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4105 Fid) - 4);
4106 pSMB->t2.DataCount = 0;
4107 pSMB->t2.DataOffset = 0;
4108 pSMB->t2.SetupCount = 1;
4109 pSMB->t2.Reserved3 = 0;
4110 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4111 byte_count = params + 1 /* pad */ ;
4112 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4113 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4114 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4115 pSMB->Pad = 0;
4116 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004117 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004118
4119 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4120 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4121 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00004122 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004123 } else { /* decode response */
4124 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4125
Jeff Layton820a8032011-05-04 08:05:26 -04004126 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004127 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response. "
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004128 "Unix Extensions can be disabled on mount "
Steve Frenchf19159d2010-04-21 04:12:10 +00004129 "by specifying the nosfu mount option.");
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004130 rc = -EIO; /* bad smb */
4131 } else {
4132 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4133 memcpy((char *) pFindData,
4134 (char *) &pSMBr->hdr.Protocol +
4135 data_offset,
4136 sizeof(FILE_UNIX_BASIC_INFO));
4137 }
4138 }
4139
4140 cifs_buf_release(pSMB);
4141 if (rc == -EAGAIN)
4142 goto UnixQFileInfoRetry;
4143
4144 return rc;
4145}
4146
4147int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004148CIFSSMBUnixQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004149 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00004150 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07004151 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004152{
4153/* SMB_QUERY_FILE_UNIX_BASIC */
4154 TRANSACTION2_QPI_REQ *pSMB = NULL;
4155 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4156 int rc = 0;
4157 int bytes_returned = 0;
4158 int name_len;
4159 __u16 params, byte_count;
4160
Joe Perchesb6b38f72010-04-21 03:50:45 +00004161 cFYI(1, "In QPathInfo (Unix) the path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004162UnixQPathInfoRetry:
4163 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4164 (void **) &pSMBr);
4165 if (rc)
4166 return rc;
4167
4168 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4169 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004170 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4171 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004172 name_len++; /* trailing null */
4173 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004174 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004175 name_len = strnlen(searchName, PATH_MAX);
4176 name_len++; /* trailing null */
4177 strncpy(pSMB->FileName, searchName, name_len);
4178 }
4179
Steve French50c2f752007-07-13 00:33:32 +00004180 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004181 pSMB->TotalDataCount = 0;
4182 pSMB->MaxParameterCount = cpu_to_le16(2);
4183 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00004184 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004185 pSMB->MaxSetupCount = 0;
4186 pSMB->Reserved = 0;
4187 pSMB->Flags = 0;
4188 pSMB->Timeout = 0;
4189 pSMB->Reserved2 = 0;
4190 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004191 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004192 pSMB->DataCount = 0;
4193 pSMB->DataOffset = 0;
4194 pSMB->SetupCount = 1;
4195 pSMB->Reserved3 = 0;
4196 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4197 byte_count = params + 1 /* pad */ ;
4198 pSMB->TotalParameterCount = cpu_to_le16(params);
4199 pSMB->ParameterCount = pSMB->TotalParameterCount;
4200 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4201 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004202 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004203 pSMB->ByteCount = cpu_to_le16(byte_count);
4204
4205 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4206 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4207 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004208 cFYI(1, "Send error in QPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004209 } else { /* decode response */
4210 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4211
Jeff Layton820a8032011-05-04 08:05:26 -04004212 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004213 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response. "
Steve French1e71f252007-09-20 15:30:07 +00004214 "Unix Extensions can be disabled on mount "
Joe Perchesb6b38f72010-04-21 03:50:45 +00004215 "by specifying the nosfu mount option.");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004216 rc = -EIO; /* bad smb */
4217 } else {
4218 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4219 memcpy((char *) pFindData,
4220 (char *) &pSMBr->hdr.Protocol +
4221 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00004222 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004223 }
4224 }
4225 cifs_buf_release(pSMB);
4226 if (rc == -EAGAIN)
4227 goto UnixQPathInfoRetry;
4228
4229 return rc;
4230}
4231
Linus Torvalds1da177e2005-04-16 15:20:36 -07004232/* xid, tcon, searchName and codepage are input parms, rest are returned */
4233int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004234CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004235 const char *searchName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004236 const struct nls_table *nls_codepage,
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004237 __u16 *pnetfid, __u16 search_flags,
Steve French50c2f752007-07-13 00:33:32 +00004238 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004239{
4240/* level 257 SMB_ */
4241 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
4242 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004243 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004244 int rc = 0;
4245 int bytes_returned = 0;
4246 int name_len;
4247 __u16 params, byte_count;
4248
Joe Perchesb6b38f72010-04-21 03:50:45 +00004249 cFYI(1, "In FindFirst for %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004250
4251findFirstRetry:
4252 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4253 (void **) &pSMBr);
4254 if (rc)
4255 return rc;
4256
4257 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4258 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004259 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4260 PATH_MAX, nls_codepage, remap);
Steve French737b7582005-04-28 22:41:06 -07004261 /* We can not add the asterik earlier in case
4262 it got remapped to 0xF03A as if it were part of the
4263 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004264 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07004265 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07004266 pSMB->FileName[name_len+1] = 0;
4267 pSMB->FileName[name_len+2] = '*';
4268 pSMB->FileName[name_len+3] = 0;
4269 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004270 pSMB->FileName[name_len] = 0; /* null terminate just in case */
4271 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07004272 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004273 } else { /* BB add check for overrun of SMB buf BB */
4274 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004275/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00004276 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004277 free buffer exit; BB */
4278 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07004279 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07004280 pSMB->FileName[name_len+1] = '*';
4281 pSMB->FileName[name_len+2] = 0;
4282 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004283 }
4284
4285 params = 12 + name_len /* includes null */ ;
4286 pSMB->TotalDataCount = 0; /* no EAs */
4287 pSMB->MaxParameterCount = cpu_to_le16(10);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004288 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004289 pSMB->MaxSetupCount = 0;
4290 pSMB->Reserved = 0;
4291 pSMB->Flags = 0;
4292 pSMB->Timeout = 0;
4293 pSMB->Reserved2 = 0;
4294 byte_count = params + 1 /* pad */ ;
4295 pSMB->TotalParameterCount = cpu_to_le16(params);
4296 pSMB->ParameterCount = pSMB->TotalParameterCount;
4297 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00004298 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
4299 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004300 pSMB->DataCount = 0;
4301 pSMB->DataOffset = 0;
4302 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
4303 pSMB->Reserved3 = 0;
4304 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
4305 pSMB->SearchAttributes =
4306 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
4307 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00004308 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004309 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004310 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4311
4312 /* BB what should we set StorageType to? Does it matter? BB */
4313 pSMB->SearchStorageType = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004314 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004315 pSMB->ByteCount = cpu_to_le16(byte_count);
4316
4317 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4318 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004319 cifs_stats_inc(&tcon->stats.cifs_stats.num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004320
Steve French88274812006-03-09 22:21:45 +00004321 if (rc) {/* BB add logic to retry regular search if Unix search
4322 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004323 /* BB Add code to handle unsupported level rc */
Joe Perchesb6b38f72010-04-21 03:50:45 +00004324 cFYI(1, "Error in FindFirst = %d", rc);
Steve French1982c342005-08-17 12:38:22 -07004325
Steve French88274812006-03-09 22:21:45 +00004326 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004327
4328 /* BB eventually could optimize out free and realloc of buf */
4329 /* for this case */
4330 if (rc == -EAGAIN)
4331 goto findFirstRetry;
4332 } else { /* decode response */
4333 /* BB remember to free buffer if error BB */
4334 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00004335 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004336 unsigned int lnoff;
4337
Linus Torvalds1da177e2005-04-16 15:20:36 -07004338 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004339 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004340 else
Steve French4b18f2a2008-04-29 00:06:05 +00004341 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004342
4343 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004344 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00004345 psrch_inf->srch_entries_start =
4346 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004347 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004348 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
4349 le16_to_cpu(pSMBr->t2.ParameterOffset));
4350
Steve French790fe572007-07-07 19:25:05 +00004351 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004352 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004353 else
Steve French4b18f2a2008-04-29 00:06:05 +00004354 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004355
Steve French50c2f752007-07-13 00:33:32 +00004356 psrch_inf->entries_in_buffer =
4357 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00004358 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004359 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004360 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004361 if (CIFSMaxBufSize < lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004362 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00004363 psrch_inf->last_entry = NULL;
4364 return rc;
4365 }
4366
Steve French0752f152008-10-07 20:03:33 +00004367 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00004368 lnoff;
4369
Linus Torvalds1da177e2005-04-16 15:20:36 -07004370 *pnetfid = parms->SearchHandle;
4371 } else {
4372 cifs_buf_release(pSMB);
4373 }
4374 }
4375
4376 return rc;
4377}
4378
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004379int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
4380 __u16 searchHandle, __u16 search_flags,
4381 struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004382{
4383 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
4384 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004385 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004386 char *response_data;
4387 int rc = 0;
Jeff Layton9438fab2011-08-23 07:21:28 -04004388 int bytes_returned;
4389 unsigned int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004390 __u16 params, byte_count;
4391
Joe Perchesb6b38f72010-04-21 03:50:45 +00004392 cFYI(1, "In FindNext");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004393
Steve French4b18f2a2008-04-29 00:06:05 +00004394 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004395 return -ENOENT;
4396
4397 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4398 (void **) &pSMBr);
4399 if (rc)
4400 return rc;
4401
Steve French50c2f752007-07-13 00:33:32 +00004402 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004403 byte_count = 0;
4404 pSMB->TotalDataCount = 0; /* no EAs */
4405 pSMB->MaxParameterCount = cpu_to_le16(8);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004406 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004407 pSMB->MaxSetupCount = 0;
4408 pSMB->Reserved = 0;
4409 pSMB->Flags = 0;
4410 pSMB->Timeout = 0;
4411 pSMB->Reserved2 = 0;
4412 pSMB->ParameterOffset = cpu_to_le16(
4413 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
4414 pSMB->DataCount = 0;
4415 pSMB->DataOffset = 0;
4416 pSMB->SetupCount = 1;
4417 pSMB->Reserved3 = 0;
4418 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
4419 pSMB->SearchHandle = searchHandle; /* always kept as le */
4420 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00004421 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004422 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4423 pSMB->ResumeKey = psrch_inf->resume_key;
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004424 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004425
4426 name_len = psrch_inf->resume_name_len;
4427 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00004428 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004429 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
4430 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07004431 /* 14 byte parm len above enough for 2 byte null terminator */
4432 pSMB->ResumeFileName[name_len] = 0;
4433 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004434 } else {
4435 rc = -EINVAL;
4436 goto FNext2_err_exit;
4437 }
4438 byte_count = params + 1 /* pad */ ;
4439 pSMB->TotalParameterCount = cpu_to_le16(params);
4440 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004441 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004442 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004443
Linus Torvalds1da177e2005-04-16 15:20:36 -07004444 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4445 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004446 cifs_stats_inc(&tcon->stats.cifs_stats.num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004447 if (rc) {
4448 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00004449 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07004450 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00004451 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004452 } else
Joe Perchesb6b38f72010-04-21 03:50:45 +00004453 cFYI(1, "FindNext returned = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004454 } else { /* decode response */
4455 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00004456
Steve French790fe572007-07-07 19:25:05 +00004457 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004458 unsigned int lnoff;
4459
Linus Torvalds1da177e2005-04-16 15:20:36 -07004460 /* BB fixme add lock for file (srch_info) struct here */
4461 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004462 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004463 else
Steve French4b18f2a2008-04-29 00:06:05 +00004464 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004465 response_data = (char *) &pSMBr->hdr.Protocol +
4466 le16_to_cpu(pSMBr->t2.ParameterOffset);
4467 parms = (T2_FNEXT_RSP_PARMS *)response_data;
4468 response_data = (char *)&pSMBr->hdr.Protocol +
4469 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00004470 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00004471 cifs_small_buf_release(
4472 psrch_inf->ntwrk_buf_start);
4473 else
4474 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004475 psrch_inf->srch_entries_start = response_data;
4476 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004477 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00004478 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004479 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004480 else
Steve French4b18f2a2008-04-29 00:06:05 +00004481 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00004482 psrch_inf->entries_in_buffer =
4483 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004484 psrch_inf->index_of_last_entry +=
4485 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004486 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004487 if (CIFSMaxBufSize < lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004488 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00004489 psrch_inf->last_entry = NULL;
4490 return rc;
4491 } else
4492 psrch_inf->last_entry =
4493 psrch_inf->srch_entries_start + lnoff;
4494
Joe Perchesb6b38f72010-04-21 03:50:45 +00004495/* cFYI(1, "fnxt2 entries in buf %d index_of_last %d",
4496 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004497
4498 /* BB fixme add unlock here */
4499 }
4500
4501 }
4502
4503 /* BB On error, should we leave previous search buf (and count and
4504 last entry fields) intact or free the previous one? */
4505
4506 /* Note: On -EAGAIN error only caller can retry on handle based calls
4507 since file handle passed in no longer valid */
4508FNext2_err_exit:
4509 if (rc != 0)
4510 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004511 return rc;
4512}
4513
4514int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004515CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004516 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004517{
4518 int rc = 0;
4519 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004520
Joe Perchesb6b38f72010-04-21 03:50:45 +00004521 cFYI(1, "In CIFSSMBFindClose");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004522 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
4523
4524 /* no sense returning error if session restarted
4525 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00004526 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004527 return 0;
4528 if (rc)
4529 return rc;
4530
Linus Torvalds1da177e2005-04-16 15:20:36 -07004531 pSMB->FileID = searchHandle;
4532 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04004533 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004534 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00004535 cERROR(1, "Send error in FindClose = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00004536
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004537 cifs_stats_inc(&tcon->stats.cifs_stats.num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004538
4539 /* Since session is dead, search handle closed on server already */
4540 if (rc == -EAGAIN)
4541 rc = 0;
4542
4543 return rc;
4544}
4545
Linus Torvalds1da177e2005-04-16 15:20:36 -07004546int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004547CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004548 const char *search_name, __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00004549 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004550{
4551 int rc = 0;
4552 TRANSACTION2_QPI_REQ *pSMB = NULL;
4553 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4554 int name_len, bytes_returned;
4555 __u16 params, byte_count;
4556
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004557 cFYI(1, "In GetSrvInodeNum for %s", search_name);
Steve French790fe572007-07-07 19:25:05 +00004558 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00004559 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004560
4561GetInodeNumberRetry:
4562 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004563 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004564 if (rc)
4565 return rc;
4566
Linus Torvalds1da177e2005-04-16 15:20:36 -07004567 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4568 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004569 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004570 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004571 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004572 name_len++; /* trailing null */
4573 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004574 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004575 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004576 name_len++; /* trailing null */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004577 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004578 }
4579
4580 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4581 pSMB->TotalDataCount = 0;
4582 pSMB->MaxParameterCount = cpu_to_le16(2);
4583 /* BB find exact max data count below from sess structure BB */
4584 pSMB->MaxDataCount = cpu_to_le16(4000);
4585 pSMB->MaxSetupCount = 0;
4586 pSMB->Reserved = 0;
4587 pSMB->Flags = 0;
4588 pSMB->Timeout = 0;
4589 pSMB->Reserved2 = 0;
4590 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004591 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004592 pSMB->DataCount = 0;
4593 pSMB->DataOffset = 0;
4594 pSMB->SetupCount = 1;
4595 pSMB->Reserved3 = 0;
4596 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4597 byte_count = params + 1 /* pad */ ;
4598 pSMB->TotalParameterCount = cpu_to_le16(params);
4599 pSMB->ParameterCount = pSMB->TotalParameterCount;
4600 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4601 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004602 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004603 pSMB->ByteCount = cpu_to_le16(byte_count);
4604
4605 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4606 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4607 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004608 cFYI(1, "error %d in QueryInternalInfo", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004609 } else {
4610 /* decode response */
4611 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004612 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04004613 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004614 /* If rc should we check for EOPNOSUPP and
4615 disable the srvino flag? or in caller? */
4616 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00004617 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004618 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4619 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00004620 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004621 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00004622 if (count < 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004623 cFYI(1, "Illegal size ret in QryIntrnlInf");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004624 rc = -EIO;
4625 goto GetInodeNumOut;
4626 }
4627 pfinfo = (struct file_internal_info *)
4628 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00004629 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004630 }
4631 }
4632GetInodeNumOut:
4633 cifs_buf_release(pSMB);
4634 if (rc == -EAGAIN)
4635 goto GetInodeNumberRetry;
4636 return rc;
4637}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004638
Igor Mammedovfec45852008-05-16 13:06:30 +04004639/* parses DFS refferal V3 structure
4640 * caller is responsible for freeing target_nodes
4641 * returns:
4642 * on success - 0
4643 * on failure - errno
4644 */
4645static int
Steve Frencha1fe78f2008-05-16 18:48:38 +00004646parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
Igor Mammedovfec45852008-05-16 13:06:30 +04004647 unsigned int *num_of_nodes,
4648 struct dfs_info3_param **target_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004649 const struct nls_table *nls_codepage, int remap,
4650 const char *searchName)
Igor Mammedovfec45852008-05-16 13:06:30 +04004651{
4652 int i, rc = 0;
4653 char *data_end;
4654 bool is_unicode;
4655 struct dfs_referral_level_3 *ref;
4656
Harvey Harrison5ca33c62008-07-23 17:45:58 -07004657 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4658 is_unicode = true;
4659 else
4660 is_unicode = false;
Igor Mammedovfec45852008-05-16 13:06:30 +04004661 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
4662
4663 if (*num_of_nodes < 1) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004664 cERROR(1, "num_referrals: must be at least > 0,"
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004665 "but we get num_referrals = %d", *num_of_nodes);
Igor Mammedovfec45852008-05-16 13:06:30 +04004666 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004667 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004668 }
4669
4670 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
Al Viro1d92cfd2008-06-02 10:59:02 +01004671 if (ref->VersionNumber != cpu_to_le16(3)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004672 cERROR(1, "Referrals of V%d version are not supported,"
4673 "should be V3", le16_to_cpu(ref->VersionNumber));
Igor Mammedovfec45852008-05-16 13:06:30 +04004674 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004675 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004676 }
4677
4678 /* get the upper boundary of the resp buffer */
4679 data_end = (char *)(&(pSMBr->PathConsumed)) +
4680 le16_to_cpu(pSMBr->t2.DataCount);
4681
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004682 cFYI(1, "num_referrals: %d dfs flags: 0x%x ...",
Igor Mammedovfec45852008-05-16 13:06:30 +04004683 *num_of_nodes,
Joe Perchesb6b38f72010-04-21 03:50:45 +00004684 le32_to_cpu(pSMBr->DFSFlags));
Igor Mammedovfec45852008-05-16 13:06:30 +04004685
4686 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
4687 *num_of_nodes, GFP_KERNEL);
4688 if (*target_nodes == NULL) {
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004689 cERROR(1, "Failed to allocate buffer for target_nodes");
Igor Mammedovfec45852008-05-16 13:06:30 +04004690 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004691 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004692 }
4693
Daniel Mack3ad2f3f2010-02-03 08:01:28 +08004694 /* collect necessary data from referrals */
Igor Mammedovfec45852008-05-16 13:06:30 +04004695 for (i = 0; i < *num_of_nodes; i++) {
4696 char *temp;
4697 int max_len;
4698 struct dfs_info3_param *node = (*target_nodes)+i;
4699
Steve French0e0d2cf2009-05-01 05:27:32 +00004700 node->flags = le32_to_cpu(pSMBr->DFSFlags);
Igor Mammedov2c556082008-10-23 13:58:42 +04004701 if (is_unicode) {
Jeff Layton331c3132008-12-17 06:31:53 -05004702 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4703 GFP_KERNEL);
Steve French2920ee22009-08-31 15:27:26 +00004704 if (tmp == NULL) {
4705 rc = -ENOMEM;
4706 goto parse_DFS_referrals_exit;
4707 }
Steve Frenchacbbb762012-01-18 22:32:33 -06004708 cifsConvertToUTF16((__le16 *) tmp, searchName,
4709 PATH_MAX, nls_codepage, remap);
4710 node->path_consumed = cifs_utf16_bytes(tmp,
Jeff Layton69f801f2009-04-30 06:46:32 -04004711 le16_to_cpu(pSMBr->PathConsumed),
Igor Mammedov2c556082008-10-23 13:58:42 +04004712 nls_codepage);
4713 kfree(tmp);
4714 } else
4715 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4716
Igor Mammedovfec45852008-05-16 13:06:30 +04004717 node->server_type = le16_to_cpu(ref->ServerType);
4718 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4719
4720 /* copy DfsPath */
4721 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4722 max_len = data_end - temp;
Steve Frenchacbbb762012-01-18 22:32:33 -06004723 node->path_name = cifs_strndup_from_utf16(temp, max_len,
4724 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004725 if (!node->path_name) {
4726 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004727 goto parse_DFS_referrals_exit;
Jeff Layton066ce682009-04-30 07:16:14 -04004728 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004729
4730 /* copy link target UNC */
4731 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4732 max_len = data_end - temp;
Steve Frenchacbbb762012-01-18 22:32:33 -06004733 node->node_name = cifs_strndup_from_utf16(temp, max_len,
4734 is_unicode, nls_codepage);
Stefan Metzmacherd8f27992012-05-04 00:19:28 +02004735 if (!node->node_name) {
Jeff Laytond8e2f532009-05-14 07:46:59 -04004736 rc = -ENOMEM;
Stefan Metzmacherd8f27992012-05-04 00:19:28 +02004737 goto parse_DFS_referrals_exit;
4738 }
4739
4740 ref++;
Igor Mammedovfec45852008-05-16 13:06:30 +04004741 }
4742
Steve Frencha1fe78f2008-05-16 18:48:38 +00004743parse_DFS_referrals_exit:
Igor Mammedovfec45852008-05-16 13:06:30 +04004744 if (rc) {
4745 free_dfs_info_array(*target_nodes, *num_of_nodes);
4746 *target_nodes = NULL;
4747 *num_of_nodes = 0;
4748 }
4749 return rc;
4750}
4751
Linus Torvalds1da177e2005-04-16 15:20:36 -07004752int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004753CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004754 const char *search_name, struct dfs_info3_param **target_nodes,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004755 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004756 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004757{
4758/* TRANS2_GET_DFS_REFERRAL */
4759 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4760 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004761 int rc = 0;
4762 int bytes_returned;
4763 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004764 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004765 *num_of_nodes = 0;
4766 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004767
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004768 cFYI(1, "In GetDFSRefer the path %s", search_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004769 if (ses == NULL)
4770 return -ENODEV;
4771getDFSRetry:
4772 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4773 (void **) &pSMBr);
4774 if (rc)
4775 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004776
4777 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004778 but should never be null here anyway */
Pavel Shilovsky88257362012-05-23 14:01:59 +04004779 pSMB->hdr.Mid = get_next_mid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004780 pSMB->hdr.Tid = ses->ipc_tid;
4781 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004782 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004783 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004784 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004785 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004786
4787 if (ses->capabilities & CAP_UNICODE) {
4788 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4789 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004790 cifsConvertToUTF16((__le16 *) pSMB->RequestFileName,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004791 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004792 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004793 name_len++; /* trailing null */
4794 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004795 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004796 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004797 name_len++; /* trailing null */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004798 strncpy(pSMB->RequestFileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004799 }
4800
Steve French790fe572007-07-07 19:25:05 +00004801 if (ses->server) {
Steve French96daf2b2011-05-27 04:34:02 +00004802 if (ses->server->sec_mode &
Steve French1a4e15a2006-10-12 21:33:51 +00004803 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4804 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4805 }
4806
Steve French50c2f752007-07-13 00:33:32 +00004807 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004808
Linus Torvalds1da177e2005-04-16 15:20:36 -07004809 params = 2 /* level */ + name_len /*includes null */ ;
4810 pSMB->TotalDataCount = 0;
4811 pSMB->DataCount = 0;
4812 pSMB->DataOffset = 0;
4813 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004814 /* BB find exact max SMB PDU from sess structure BB */
4815 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004816 pSMB->MaxSetupCount = 0;
4817 pSMB->Reserved = 0;
4818 pSMB->Flags = 0;
4819 pSMB->Timeout = 0;
4820 pSMB->Reserved2 = 0;
4821 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004822 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004823 pSMB->SetupCount = 1;
4824 pSMB->Reserved3 = 0;
4825 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4826 byte_count = params + 3 /* pad */ ;
4827 pSMB->ParameterCount = cpu_to_le16(params);
4828 pSMB->TotalParameterCount = pSMB->ParameterCount;
4829 pSMB->MaxReferralLevel = cpu_to_le16(3);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004830 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004831 pSMB->ByteCount = cpu_to_le16(byte_count);
4832
4833 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4834 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4835 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004836 cFYI(1, "Send error in GetDFSRefer = %d", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004837 goto GetDFSRefExit;
4838 }
4839 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004840
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004841 /* BB Also check if enough total bytes returned? */
Jeff Layton820a8032011-05-04 08:05:26 -04004842 if (rc || get_bcc(&pSMBr->hdr) < 17) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004843 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004844 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004845 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004846
Joe Perchesb6b38f72010-04-21 03:50:45 +00004847 cFYI(1, "Decoding GetDFSRefer response BCC: %d Offset %d",
Jeff Layton820a8032011-05-04 08:05:26 -04004848 get_bcc(&pSMBr->hdr),
Joe Perchesb6b38f72010-04-21 03:50:45 +00004849 le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04004850
4851 /* parse returned result into more usable form */
Steve Frencha1fe78f2008-05-16 18:48:38 +00004852 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004853 target_nodes, nls_codepage, remap,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004854 search_name);
Igor Mammedovfec45852008-05-16 13:06:30 +04004855
Linus Torvalds1da177e2005-04-16 15:20:36 -07004856GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004857 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004858
4859 if (rc == -EAGAIN)
4860 goto getDFSRetry;
4861
4862 return rc;
4863}
4864
Steve French20962432005-09-21 22:05:57 -07004865/* Query File System Info such as free space to old servers such as Win 9x */
4866int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004867SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4868 struct kstatfs *FSData)
Steve French20962432005-09-21 22:05:57 -07004869{
4870/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4871 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4872 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4873 FILE_SYSTEM_ALLOC_INFO *response_data;
4874 int rc = 0;
4875 int bytes_returned = 0;
4876 __u16 params, byte_count;
4877
Joe Perchesb6b38f72010-04-21 03:50:45 +00004878 cFYI(1, "OldQFSInfo");
Steve French20962432005-09-21 22:05:57 -07004879oldQFSInfoRetry:
4880 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4881 (void **) &pSMBr);
4882 if (rc)
4883 return rc;
Steve French20962432005-09-21 22:05:57 -07004884
4885 params = 2; /* level */
4886 pSMB->TotalDataCount = 0;
4887 pSMB->MaxParameterCount = cpu_to_le16(2);
4888 pSMB->MaxDataCount = cpu_to_le16(1000);
4889 pSMB->MaxSetupCount = 0;
4890 pSMB->Reserved = 0;
4891 pSMB->Flags = 0;
4892 pSMB->Timeout = 0;
4893 pSMB->Reserved2 = 0;
4894 byte_count = params + 1 /* pad */ ;
4895 pSMB->TotalParameterCount = cpu_to_le16(params);
4896 pSMB->ParameterCount = pSMB->TotalParameterCount;
4897 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4898 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4899 pSMB->DataCount = 0;
4900 pSMB->DataOffset = 0;
4901 pSMB->SetupCount = 1;
4902 pSMB->Reserved3 = 0;
4903 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4904 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004905 inc_rfc1001_len(pSMB, byte_count);
Steve French20962432005-09-21 22:05:57 -07004906 pSMB->ByteCount = cpu_to_le16(byte_count);
4907
4908 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4909 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4910 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004911 cFYI(1, "Send error in QFSInfo = %d", rc);
Steve French20962432005-09-21 22:05:57 -07004912 } else { /* decode response */
4913 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4914
Jeff Layton820a8032011-05-04 08:05:26 -04004915 if (rc || get_bcc(&pSMBr->hdr) < 18)
Steve French20962432005-09-21 22:05:57 -07004916 rc = -EIO; /* bad smb */
4917 else {
4918 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004919 cFYI(1, "qfsinf resp BCC: %d Offset %d",
Jeff Layton820a8032011-05-04 08:05:26 -04004920 get_bcc(&pSMBr->hdr), data_offset);
Steve French20962432005-09-21 22:05:57 -07004921
Steve French50c2f752007-07-13 00:33:32 +00004922 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004923 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4924 FSData->f_bsize =
4925 le16_to_cpu(response_data->BytesPerSector) *
4926 le32_to_cpu(response_data->
4927 SectorsPerAllocationUnit);
4928 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004929 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004930 FSData->f_bfree = FSData->f_bavail =
4931 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004932 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
4933 (unsigned long long)FSData->f_blocks,
4934 (unsigned long long)FSData->f_bfree,
4935 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07004936 }
4937 }
4938 cifs_buf_release(pSMB);
4939
4940 if (rc == -EAGAIN)
4941 goto oldQFSInfoRetry;
4942
4943 return rc;
4944}
4945
Linus Torvalds1da177e2005-04-16 15:20:36 -07004946int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004947CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4948 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004949{
4950/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4951 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4952 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4953 FILE_SYSTEM_INFO *response_data;
4954 int rc = 0;
4955 int bytes_returned = 0;
4956 __u16 params, byte_count;
4957
Joe Perchesb6b38f72010-04-21 03:50:45 +00004958 cFYI(1, "In QFSInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004959QFSInfoRetry:
4960 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4961 (void **) &pSMBr);
4962 if (rc)
4963 return rc;
4964
4965 params = 2; /* level */
4966 pSMB->TotalDataCount = 0;
4967 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004968 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004969 pSMB->MaxSetupCount = 0;
4970 pSMB->Reserved = 0;
4971 pSMB->Flags = 0;
4972 pSMB->Timeout = 0;
4973 pSMB->Reserved2 = 0;
4974 byte_count = params + 1 /* pad */ ;
4975 pSMB->TotalParameterCount = cpu_to_le16(params);
4976 pSMB->ParameterCount = pSMB->TotalParameterCount;
4977 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004978 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004979 pSMB->DataCount = 0;
4980 pSMB->DataOffset = 0;
4981 pSMB->SetupCount = 1;
4982 pSMB->Reserved3 = 0;
4983 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4984 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004985 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004986 pSMB->ByteCount = cpu_to_le16(byte_count);
4987
4988 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4989 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4990 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004991 cFYI(1, "Send error in QFSInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004992 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00004993 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004994
Jeff Layton820a8032011-05-04 08:05:26 -04004995 if (rc || get_bcc(&pSMBr->hdr) < 24)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004996 rc = -EIO; /* bad smb */
4997 else {
4998 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004999
5000 response_data =
5001 (FILE_SYSTEM_INFO
5002 *) (((char *) &pSMBr->hdr.Protocol) +
5003 data_offset);
5004 FSData->f_bsize =
5005 le32_to_cpu(response_data->BytesPerSector) *
5006 le32_to_cpu(response_data->
5007 SectorsPerAllocationUnit);
5008 FSData->f_blocks =
5009 le64_to_cpu(response_data->TotalAllocationUnits);
5010 FSData->f_bfree = FSData->f_bavail =
5011 le64_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesb6b38f72010-04-21 03:50:45 +00005012 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
5013 (unsigned long long)FSData->f_blocks,
5014 (unsigned long long)FSData->f_bfree,
5015 FSData->f_bsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005016 }
5017 }
5018 cifs_buf_release(pSMB);
5019
5020 if (rc == -EAGAIN)
5021 goto QFSInfoRetry;
5022
5023 return rc;
5024}
5025
5026int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005027CIFSSMBQFSAttributeInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005028{
5029/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
5030 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5031 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5032 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
5033 int rc = 0;
5034 int bytes_returned = 0;
5035 __u16 params, byte_count;
5036
Joe Perchesb6b38f72010-04-21 03:50:45 +00005037 cFYI(1, "In QFSAttributeInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005038QFSAttributeRetry:
5039 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5040 (void **) &pSMBr);
5041 if (rc)
5042 return rc;
5043
5044 params = 2; /* level */
5045 pSMB->TotalDataCount = 0;
5046 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005047 /* BB find exact max SMB PDU from sess structure BB */
5048 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005049 pSMB->MaxSetupCount = 0;
5050 pSMB->Reserved = 0;
5051 pSMB->Flags = 0;
5052 pSMB->Timeout = 0;
5053 pSMB->Reserved2 = 0;
5054 byte_count = params + 1 /* pad */ ;
5055 pSMB->TotalParameterCount = cpu_to_le16(params);
5056 pSMB->ParameterCount = pSMB->TotalParameterCount;
5057 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005058 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005059 pSMB->DataCount = 0;
5060 pSMB->DataOffset = 0;
5061 pSMB->SetupCount = 1;
5062 pSMB->Reserved3 = 0;
5063 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5064 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005065 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005066 pSMB->ByteCount = cpu_to_le16(byte_count);
5067
5068 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5069 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5070 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005071 cERROR(1, "Send error in QFSAttributeInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005072 } else { /* decode response */
5073 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5074
Jeff Layton820a8032011-05-04 08:05:26 -04005075 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Steve French50c2f752007-07-13 00:33:32 +00005076 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005077 rc = -EIO; /* bad smb */
5078 } else {
5079 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5080 response_data =
5081 (FILE_SYSTEM_ATTRIBUTE_INFO
5082 *) (((char *) &pSMBr->hdr.Protocol) +
5083 data_offset);
5084 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005085 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005086 }
5087 }
5088 cifs_buf_release(pSMB);
5089
5090 if (rc == -EAGAIN)
5091 goto QFSAttributeRetry;
5092
5093 return rc;
5094}
5095
5096int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005097CIFSSMBQFSDeviceInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005098{
5099/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
5100 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5101 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5102 FILE_SYSTEM_DEVICE_INFO *response_data;
5103 int rc = 0;
5104 int bytes_returned = 0;
5105 __u16 params, byte_count;
5106
Joe Perchesb6b38f72010-04-21 03:50:45 +00005107 cFYI(1, "In QFSDeviceInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005108QFSDeviceRetry:
5109 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5110 (void **) &pSMBr);
5111 if (rc)
5112 return rc;
5113
5114 params = 2; /* level */
5115 pSMB->TotalDataCount = 0;
5116 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005117 /* BB find exact max SMB PDU from sess structure BB */
5118 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005119 pSMB->MaxSetupCount = 0;
5120 pSMB->Reserved = 0;
5121 pSMB->Flags = 0;
5122 pSMB->Timeout = 0;
5123 pSMB->Reserved2 = 0;
5124 byte_count = params + 1 /* pad */ ;
5125 pSMB->TotalParameterCount = cpu_to_le16(params);
5126 pSMB->ParameterCount = pSMB->TotalParameterCount;
5127 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005128 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005129
5130 pSMB->DataCount = 0;
5131 pSMB->DataOffset = 0;
5132 pSMB->SetupCount = 1;
5133 pSMB->Reserved3 = 0;
5134 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5135 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005136 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005137 pSMB->ByteCount = cpu_to_le16(byte_count);
5138
5139 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5140 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5141 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005142 cFYI(1, "Send error in QFSDeviceInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005143 } else { /* decode response */
5144 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5145
Jeff Layton820a8032011-05-04 08:05:26 -04005146 if (rc || get_bcc(&pSMBr->hdr) <
5147 sizeof(FILE_SYSTEM_DEVICE_INFO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005148 rc = -EIO; /* bad smb */
5149 else {
5150 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5151 response_data =
Steve French737b7582005-04-28 22:41:06 -07005152 (FILE_SYSTEM_DEVICE_INFO *)
5153 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07005154 data_offset);
5155 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005156 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005157 }
5158 }
5159 cifs_buf_release(pSMB);
5160
5161 if (rc == -EAGAIN)
5162 goto QFSDeviceRetry;
5163
5164 return rc;
5165}
5166
5167int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005168CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005169{
5170/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
5171 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5172 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5173 FILE_SYSTEM_UNIX_INFO *response_data;
5174 int rc = 0;
5175 int bytes_returned = 0;
5176 __u16 params, byte_count;
5177
Joe Perchesb6b38f72010-04-21 03:50:45 +00005178 cFYI(1, "In QFSUnixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005179QFSUnixRetry:
Jeff Laytonf5695992010-09-29 15:27:08 -04005180 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5181 (void **) &pSMB, (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005182 if (rc)
5183 return rc;
5184
5185 params = 2; /* level */
5186 pSMB->TotalDataCount = 0;
5187 pSMB->DataCount = 0;
5188 pSMB->DataOffset = 0;
5189 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005190 /* BB find exact max SMB PDU from sess structure BB */
5191 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005192 pSMB->MaxSetupCount = 0;
5193 pSMB->Reserved = 0;
5194 pSMB->Flags = 0;
5195 pSMB->Timeout = 0;
5196 pSMB->Reserved2 = 0;
5197 byte_count = params + 1 /* pad */ ;
5198 pSMB->ParameterCount = cpu_to_le16(params);
5199 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005200 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5201 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005202 pSMB->SetupCount = 1;
5203 pSMB->Reserved3 = 0;
5204 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5205 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005206 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005207 pSMB->ByteCount = cpu_to_le16(byte_count);
5208
5209 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5210 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5211 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005212 cERROR(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005213 } else { /* decode response */
5214 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5215
Jeff Layton820a8032011-05-04 08:05:26 -04005216 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005217 rc = -EIO; /* bad smb */
5218 } else {
5219 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5220 response_data =
5221 (FILE_SYSTEM_UNIX_INFO
5222 *) (((char *) &pSMBr->hdr.Protocol) +
5223 data_offset);
5224 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005225 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005226 }
5227 }
5228 cifs_buf_release(pSMB);
5229
5230 if (rc == -EAGAIN)
5231 goto QFSUnixRetry;
5232
5233
5234 return rc;
5235}
5236
Jeremy Allisonac670552005-06-22 17:26:35 -07005237int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005238CIFSSMBSetFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07005239{
5240/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
5241 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
5242 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
5243 int rc = 0;
5244 int bytes_returned = 0;
5245 __u16 params, param_offset, offset, byte_count;
5246
Joe Perchesb6b38f72010-04-21 03:50:45 +00005247 cFYI(1, "In SETFSUnixInfo");
Jeremy Allisonac670552005-06-22 17:26:35 -07005248SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00005249 /* BB switch to small buf init to save memory */
Jeff Laytonf5695992010-09-29 15:27:08 -04005250 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5251 (void **) &pSMB, (void **) &pSMBr);
Jeremy Allisonac670552005-06-22 17:26:35 -07005252 if (rc)
5253 return rc;
5254
5255 params = 4; /* 2 bytes zero followed by info level. */
5256 pSMB->MaxSetupCount = 0;
5257 pSMB->Reserved = 0;
5258 pSMB->Flags = 0;
5259 pSMB->Timeout = 0;
5260 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00005261 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
5262 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07005263 offset = param_offset + params;
5264
5265 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00005266 /* BB find exact max SMB PDU from sess structure BB */
5267 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07005268 pSMB->SetupCount = 1;
5269 pSMB->Reserved3 = 0;
5270 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
5271 byte_count = 1 /* pad */ + params + 12;
5272
5273 pSMB->DataCount = cpu_to_le16(12);
5274 pSMB->ParameterCount = cpu_to_le16(params);
5275 pSMB->TotalDataCount = pSMB->DataCount;
5276 pSMB->TotalParameterCount = pSMB->ParameterCount;
5277 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5278 pSMB->DataOffset = cpu_to_le16(offset);
5279
5280 /* Params. */
5281 pSMB->FileNum = 0;
5282 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
5283
5284 /* Data. */
5285 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
5286 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
5287 pSMB->ClientUnixCap = cpu_to_le64(cap);
5288
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005289 inc_rfc1001_len(pSMB, byte_count);
Jeremy Allisonac670552005-06-22 17:26:35 -07005290 pSMB->ByteCount = cpu_to_le16(byte_count);
5291
5292 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5293 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5294 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005295 cERROR(1, "Send error in SETFSUnixInfo = %d", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07005296 } else { /* decode response */
5297 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00005298 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07005299 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07005300 }
5301 cifs_buf_release(pSMB);
5302
5303 if (rc == -EAGAIN)
5304 goto SETFSUnixRetry;
5305
5306 return rc;
5307}
5308
5309
Linus Torvalds1da177e2005-04-16 15:20:36 -07005310
5311int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005312CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon,
Steve French737b7582005-04-28 22:41:06 -07005313 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005314{
5315/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
5316 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5317 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5318 FILE_SYSTEM_POSIX_INFO *response_data;
5319 int rc = 0;
5320 int bytes_returned = 0;
5321 __u16 params, byte_count;
5322
Joe Perchesb6b38f72010-04-21 03:50:45 +00005323 cFYI(1, "In QFSPosixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005324QFSPosixRetry:
5325 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5326 (void **) &pSMBr);
5327 if (rc)
5328 return rc;
5329
5330 params = 2; /* level */
5331 pSMB->TotalDataCount = 0;
5332 pSMB->DataCount = 0;
5333 pSMB->DataOffset = 0;
5334 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005335 /* BB find exact max SMB PDU from sess structure BB */
5336 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005337 pSMB->MaxSetupCount = 0;
5338 pSMB->Reserved = 0;
5339 pSMB->Flags = 0;
5340 pSMB->Timeout = 0;
5341 pSMB->Reserved2 = 0;
5342 byte_count = params + 1 /* pad */ ;
5343 pSMB->ParameterCount = cpu_to_le16(params);
5344 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005345 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5346 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005347 pSMB->SetupCount = 1;
5348 pSMB->Reserved3 = 0;
5349 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5350 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005351 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005352 pSMB->ByteCount = cpu_to_le16(byte_count);
5353
5354 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5355 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5356 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005357 cFYI(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005358 } else { /* decode response */
5359 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5360
Jeff Layton820a8032011-05-04 08:05:26 -04005361 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005362 rc = -EIO; /* bad smb */
5363 } else {
5364 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5365 response_data =
5366 (FILE_SYSTEM_POSIX_INFO
5367 *) (((char *) &pSMBr->hdr.Protocol) +
5368 data_offset);
5369 FSData->f_bsize =
5370 le32_to_cpu(response_data->BlockSize);
5371 FSData->f_blocks =
5372 le64_to_cpu(response_data->TotalBlocks);
5373 FSData->f_bfree =
5374 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00005375 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005376 FSData->f_bavail = FSData->f_bfree;
5377 } else {
5378 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00005379 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005380 }
Steve French790fe572007-07-07 19:25:05 +00005381 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005382 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00005383 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00005384 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005385 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00005386 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005387 }
5388 }
5389 cifs_buf_release(pSMB);
5390
5391 if (rc == -EAGAIN)
5392 goto QFSPosixRetry;
5393
5394 return rc;
5395}
5396
5397
Steve French50c2f752007-07-13 00:33:32 +00005398/* We can not use write of zero bytes trick to
5399 set file size due to need for large file support. Also note that
5400 this SetPathInfo is preferred to SetFileInfo based method in next
Linus Torvalds1da177e2005-04-16 15:20:36 -07005401 routine which is only needed to work around a sharing violation bug
5402 in Samba which this routine can run into */
5403
5404int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005405CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
5406 const char *fileName, __u64 size, bool SetAllocation,
Steve French737b7582005-04-28 22:41:06 -07005407 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005408{
5409 struct smb_com_transaction2_spi_req *pSMB = NULL;
5410 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5411 struct file_end_of_file_info *parm_data;
5412 int name_len;
5413 int rc = 0;
5414 int bytes_returned = 0;
5415 __u16 params, byte_count, data_count, param_offset, offset;
5416
Joe Perchesb6b38f72010-04-21 03:50:45 +00005417 cFYI(1, "In SetEOF");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005418SetEOFRetry:
5419 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5420 (void **) &pSMBr);
5421 if (rc)
5422 return rc;
5423
5424 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5425 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005426 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5427 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005428 name_len++; /* trailing null */
5429 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005430 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005431 name_len = strnlen(fileName, PATH_MAX);
5432 name_len++; /* trailing null */
5433 strncpy(pSMB->FileName, fileName, name_len);
5434 }
5435 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005436 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005437 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07005438 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005439 pSMB->MaxSetupCount = 0;
5440 pSMB->Reserved = 0;
5441 pSMB->Flags = 0;
5442 pSMB->Timeout = 0;
5443 pSMB->Reserved2 = 0;
5444 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005445 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005446 offset = param_offset + params;
Steve French790fe572007-07-07 19:25:05 +00005447 if (SetAllocation) {
Steve French50c2f752007-07-13 00:33:32 +00005448 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5449 pSMB->InformationLevel =
5450 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5451 else
5452 pSMB->InformationLevel =
5453 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5454 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005455 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5456 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005457 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005458 else
5459 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005460 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005461 }
5462
5463 parm_data =
5464 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
5465 offset);
5466 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5467 pSMB->DataOffset = cpu_to_le16(offset);
5468 pSMB->SetupCount = 1;
5469 pSMB->Reserved3 = 0;
5470 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5471 byte_count = 3 /* pad */ + params + data_count;
5472 pSMB->DataCount = cpu_to_le16(data_count);
5473 pSMB->TotalDataCount = pSMB->DataCount;
5474 pSMB->ParameterCount = cpu_to_le16(params);
5475 pSMB->TotalParameterCount = pSMB->ParameterCount;
5476 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005477 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005478 parm_data->FileSize = cpu_to_le64(size);
5479 pSMB->ByteCount = cpu_to_le16(byte_count);
5480 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5481 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005482 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005483 cFYI(1, "SetPathInfo (file size) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005484
5485 cifs_buf_release(pSMB);
5486
5487 if (rc == -EAGAIN)
5488 goto SetEOFRetry;
5489
5490 return rc;
5491}
5492
5493int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005494CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon, __u64 size,
Steve French4b18f2a2008-04-29 00:06:05 +00005495 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005496{
5497 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005498 struct file_end_of_file_info *parm_data;
5499 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005500 __u16 params, param_offset, offset, byte_count, count;
5501
Joe Perchesb6b38f72010-04-21 03:50:45 +00005502 cFYI(1, "SetFileSize (via SetFileInfo) %lld",
5503 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07005504 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5505
Linus Torvalds1da177e2005-04-16 15:20:36 -07005506 if (rc)
5507 return rc;
5508
5509 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5510 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005511
Linus Torvalds1da177e2005-04-16 15:20:36 -07005512 params = 6;
5513 pSMB->MaxSetupCount = 0;
5514 pSMB->Reserved = 0;
5515 pSMB->Flags = 0;
5516 pSMB->Timeout = 0;
5517 pSMB->Reserved2 = 0;
5518 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5519 offset = param_offset + params;
5520
Linus Torvalds1da177e2005-04-16 15:20:36 -07005521 count = sizeof(struct file_end_of_file_info);
5522 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005523 /* BB find exact max SMB PDU from sess structure BB */
5524 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005525 pSMB->SetupCount = 1;
5526 pSMB->Reserved3 = 0;
5527 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5528 byte_count = 3 /* pad */ + params + count;
5529 pSMB->DataCount = cpu_to_le16(count);
5530 pSMB->ParameterCount = cpu_to_le16(params);
5531 pSMB->TotalDataCount = pSMB->DataCount;
5532 pSMB->TotalParameterCount = pSMB->ParameterCount;
5533 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5534 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00005535 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
5536 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005537 pSMB->DataOffset = cpu_to_le16(offset);
5538 parm_data->FileSize = cpu_to_le64(size);
5539 pSMB->Fid = fid;
Steve French790fe572007-07-07 19:25:05 +00005540 if (SetAllocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005541 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5542 pSMB->InformationLevel =
5543 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5544 else
5545 pSMB->InformationLevel =
5546 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00005547 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005548 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5549 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005550 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005551 else
5552 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005553 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005554 }
5555 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005556 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005557 pSMB->ByteCount = cpu_to_le16(byte_count);
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005558 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005559 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005560 cFYI(1, "Send error in SetFileInfo (SetFileSize) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005561 }
5562
Steve French50c2f752007-07-13 00:33:32 +00005563 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005564 since file handle passed in no longer valid */
5565
5566 return rc;
5567}
5568
Steve French50c2f752007-07-13 00:33:32 +00005569/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07005570 an open handle, rather than by pathname - this is awkward due to
5571 potential access conflicts on the open, but it is unavoidable for these
5572 old servers since the only other choice is to go from 100 nanosecond DCE
5573 time and resort to the original setpathinfo level which takes the ancient
5574 DOS time format with 2 second granularity */
5575int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005576CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005577 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005578{
5579 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005580 char *data_offset;
5581 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005582 __u16 params, param_offset, offset, byte_count, count;
5583
Joe Perchesb6b38f72010-04-21 03:50:45 +00005584 cFYI(1, "Set Times (via SetFileInfo)");
Steve Frenchcd634992005-04-28 22:41:10 -07005585 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5586
Linus Torvalds1da177e2005-04-16 15:20:36 -07005587 if (rc)
5588 return rc;
5589
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005590 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5591 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005592
Linus Torvalds1da177e2005-04-16 15:20:36 -07005593 params = 6;
5594 pSMB->MaxSetupCount = 0;
5595 pSMB->Reserved = 0;
5596 pSMB->Flags = 0;
5597 pSMB->Timeout = 0;
5598 pSMB->Reserved2 = 0;
5599 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5600 offset = param_offset + params;
5601
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005602 data_offset = (char *)pSMB +
5603 offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005604
Steve French26f57362007-08-30 22:09:15 +00005605 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005606 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005607 /* BB find max SMB PDU from sess */
5608 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005609 pSMB->SetupCount = 1;
5610 pSMB->Reserved3 = 0;
5611 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5612 byte_count = 3 /* pad */ + params + count;
5613 pSMB->DataCount = cpu_to_le16(count);
5614 pSMB->ParameterCount = cpu_to_le16(params);
5615 pSMB->TotalDataCount = pSMB->DataCount;
5616 pSMB->TotalParameterCount = pSMB->ParameterCount;
5617 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5618 pSMB->DataOffset = cpu_to_le16(offset);
5619 pSMB->Fid = fid;
5620 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5621 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5622 else
5623 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5624 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005625 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005626 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005627 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005628 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005629 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005630 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005631
Steve French50c2f752007-07-13 00:33:32 +00005632 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005633 since file handle passed in no longer valid */
5634
5635 return rc;
5636}
5637
Jeff Layton6d22f092008-09-23 11:48:35 -04005638int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005639CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6d22f092008-09-23 11:48:35 -04005640 bool delete_file, __u16 fid, __u32 pid_of_opener)
5641{
5642 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5643 char *data_offset;
5644 int rc = 0;
5645 __u16 params, param_offset, offset, byte_count, count;
5646
Joe Perchesb6b38f72010-04-21 03:50:45 +00005647 cFYI(1, "Set File Disposition (via SetFileInfo)");
Jeff Layton6d22f092008-09-23 11:48:35 -04005648 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5649
5650 if (rc)
5651 return rc;
5652
5653 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5654 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5655
5656 params = 6;
5657 pSMB->MaxSetupCount = 0;
5658 pSMB->Reserved = 0;
5659 pSMB->Flags = 0;
5660 pSMB->Timeout = 0;
5661 pSMB->Reserved2 = 0;
5662 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5663 offset = param_offset + params;
5664
5665 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5666
5667 count = 1;
5668 pSMB->MaxParameterCount = cpu_to_le16(2);
5669 /* BB find max SMB PDU from sess */
5670 pSMB->MaxDataCount = cpu_to_le16(1000);
5671 pSMB->SetupCount = 1;
5672 pSMB->Reserved3 = 0;
5673 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5674 byte_count = 3 /* pad */ + params + count;
5675 pSMB->DataCount = cpu_to_le16(count);
5676 pSMB->ParameterCount = cpu_to_le16(params);
5677 pSMB->TotalDataCount = pSMB->DataCount;
5678 pSMB->TotalParameterCount = pSMB->ParameterCount;
5679 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5680 pSMB->DataOffset = cpu_to_le16(offset);
5681 pSMB->Fid = fid;
5682 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5683 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005684 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton6d22f092008-09-23 11:48:35 -04005685 pSMB->ByteCount = cpu_to_le16(byte_count);
5686 *data_offset = delete_file ? 1 : 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005687 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Jeff Layton6d22f092008-09-23 11:48:35 -04005688 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005689 cFYI(1, "Send error in SetFileDisposition = %d", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005690
5691 return rc;
5692}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005693
5694int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005695CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6fc000e2008-08-02 07:26:12 -04005696 const char *fileName, const FILE_BASIC_INFO *data,
5697 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005698{
5699 TRANSACTION2_SPI_REQ *pSMB = NULL;
5700 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5701 int name_len;
5702 int rc = 0;
5703 int bytes_returned = 0;
5704 char *data_offset;
5705 __u16 params, param_offset, offset, byte_count, count;
5706
Joe Perchesb6b38f72010-04-21 03:50:45 +00005707 cFYI(1, "In SetTimes");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005708
5709SetTimesRetry:
5710 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5711 (void **) &pSMBr);
5712 if (rc)
5713 return rc;
5714
5715 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5716 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005717 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5718 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005719 name_len++; /* trailing null */
5720 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005721 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005722 name_len = strnlen(fileName, PATH_MAX);
5723 name_len++; /* trailing null */
5724 strncpy(pSMB->FileName, fileName, name_len);
5725 }
5726
5727 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005728 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005729 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005730 /* BB find max SMB PDU from sess structure BB */
5731 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005732 pSMB->MaxSetupCount = 0;
5733 pSMB->Reserved = 0;
5734 pSMB->Flags = 0;
5735 pSMB->Timeout = 0;
5736 pSMB->Reserved2 = 0;
5737 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005738 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005739 offset = param_offset + params;
5740 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5741 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5742 pSMB->DataOffset = cpu_to_le16(offset);
5743 pSMB->SetupCount = 1;
5744 pSMB->Reserved3 = 0;
5745 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5746 byte_count = 3 /* pad */ + params + count;
5747
5748 pSMB->DataCount = cpu_to_le16(count);
5749 pSMB->ParameterCount = cpu_to_le16(params);
5750 pSMB->TotalDataCount = pSMB->DataCount;
5751 pSMB->TotalParameterCount = pSMB->ParameterCount;
5752 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5753 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5754 else
5755 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5756 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005757 inc_rfc1001_len(pSMB, byte_count);
Steve French26f57362007-08-30 22:09:15 +00005758 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005759 pSMB->ByteCount = cpu_to_le16(byte_count);
5760 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5761 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005762 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005763 cFYI(1, "SetPathInfo (times) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005764
5765 cifs_buf_release(pSMB);
5766
5767 if (rc == -EAGAIN)
5768 goto SetTimesRetry;
5769
5770 return rc;
5771}
5772
5773/* Can not be used to set time stamps yet (due to old DOS time format) */
5774/* Can be used to set attributes */
5775#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5776 handling it anyway and NT4 was what we thought it would be needed for
5777 Do not delete it until we prove whether needed for Win9x though */
5778int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005779CIFSSMBSetAttrLegacy(unsigned int xid, struct cifs_tcon *tcon, char *fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005780 __u16 dos_attrs, const struct nls_table *nls_codepage)
5781{
5782 SETATTR_REQ *pSMB = NULL;
5783 SETATTR_RSP *pSMBr = NULL;
5784 int rc = 0;
5785 int bytes_returned;
5786 int name_len;
5787
Joe Perchesb6b38f72010-04-21 03:50:45 +00005788 cFYI(1, "In SetAttrLegacy");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005789
5790SetAttrLgcyRetry:
5791 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5792 (void **) &pSMBr);
5793 if (rc)
5794 return rc;
5795
5796 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5797 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005798 ConvertToUTF16((__le16 *) pSMB->fileName, fileName,
5799 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005800 name_len++; /* trailing null */
5801 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005802 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005803 name_len = strnlen(fileName, PATH_MAX);
5804 name_len++; /* trailing null */
5805 strncpy(pSMB->fileName, fileName, name_len);
5806 }
5807 pSMB->attr = cpu_to_le16(dos_attrs);
5808 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005809 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005810 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5811 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5812 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005813 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005814 cFYI(1, "Error in LegacySetAttr = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005815
5816 cifs_buf_release(pSMB);
5817
5818 if (rc == -EAGAIN)
5819 goto SetAttrLgcyRetry;
5820
5821 return rc;
5822}
5823#endif /* temporarily unneeded SetAttr legacy function */
5824
Jeff Layton654cf142009-07-09 20:02:49 -04005825static void
5826cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5827 const struct cifs_unix_set_info_args *args)
5828{
5829 u64 mode = args->mode;
5830
5831 /*
5832 * Samba server ignores set of file size to zero due to bugs in some
5833 * older clients, but we should be precise - we use SetFileSize to
5834 * set file size and do not want to truncate file size to zero
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005835 * accidentally as happened on one Samba server beta by putting
Jeff Layton654cf142009-07-09 20:02:49 -04005836 * zero instead of -1 here
5837 */
5838 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5839 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5840 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5841 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5842 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5843 data_offset->Uid = cpu_to_le64(args->uid);
5844 data_offset->Gid = cpu_to_le64(args->gid);
5845 /* better to leave device as zero when it is */
5846 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5847 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5848 data_offset->Permissions = cpu_to_le64(mode);
5849
5850 if (S_ISREG(mode))
5851 data_offset->Type = cpu_to_le32(UNIX_FILE);
5852 else if (S_ISDIR(mode))
5853 data_offset->Type = cpu_to_le32(UNIX_DIR);
5854 else if (S_ISLNK(mode))
5855 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5856 else if (S_ISCHR(mode))
5857 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5858 else if (S_ISBLK(mode))
5859 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5860 else if (S_ISFIFO(mode))
5861 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5862 else if (S_ISSOCK(mode))
5863 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5864}
5865
Linus Torvalds1da177e2005-04-16 15:20:36 -07005866int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005867CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005868 const struct cifs_unix_set_info_args *args,
5869 u16 fid, u32 pid_of_opener)
5870{
5871 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005872 char *data_offset;
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005873 int rc = 0;
5874 u16 params, param_offset, offset, byte_count, count;
5875
Joe Perchesb6b38f72010-04-21 03:50:45 +00005876 cFYI(1, "Set Unix Info (via SetFileInfo)");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005877 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5878
5879 if (rc)
5880 return rc;
5881
5882 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5883 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5884
5885 params = 6;
5886 pSMB->MaxSetupCount = 0;
5887 pSMB->Reserved = 0;
5888 pSMB->Flags = 0;
5889 pSMB->Timeout = 0;
5890 pSMB->Reserved2 = 0;
5891 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5892 offset = param_offset + params;
5893
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005894 data_offset = (char *)pSMB +
5895 offsetof(struct smb_hdr, Protocol) + offset;
5896
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005897 count = sizeof(FILE_UNIX_BASIC_INFO);
5898
5899 pSMB->MaxParameterCount = cpu_to_le16(2);
5900 /* BB find max SMB PDU from sess */
5901 pSMB->MaxDataCount = cpu_to_le16(1000);
5902 pSMB->SetupCount = 1;
5903 pSMB->Reserved3 = 0;
5904 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5905 byte_count = 3 /* pad */ + params + count;
5906 pSMB->DataCount = cpu_to_le16(count);
5907 pSMB->ParameterCount = cpu_to_le16(params);
5908 pSMB->TotalDataCount = pSMB->DataCount;
5909 pSMB->TotalParameterCount = pSMB->ParameterCount;
5910 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5911 pSMB->DataOffset = cpu_to_le16(offset);
5912 pSMB->Fid = fid;
5913 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5914 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005915 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005916 pSMB->ByteCount = cpu_to_le16(byte_count);
5917
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005918 cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005919
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005920 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005921 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005922 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005923
5924 /* Note: On -EAGAIN error only caller can retry on handle based calls
5925 since file handle passed in no longer valid */
5926
5927 return rc;
5928}
5929
5930int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005931CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005932 const char *file_name,
Jeff Layton01ea95e2009-07-09 20:02:49 -04005933 const struct cifs_unix_set_info_args *args,
5934 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005935{
5936 TRANSACTION2_SPI_REQ *pSMB = NULL;
5937 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5938 int name_len;
5939 int rc = 0;
5940 int bytes_returned = 0;
5941 FILE_UNIX_BASIC_INFO *data_offset;
5942 __u16 params, param_offset, offset, count, byte_count;
5943
Joe Perchesb6b38f72010-04-21 03:50:45 +00005944 cFYI(1, "In SetUID/GID/Mode");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005945setPermsRetry:
5946 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5947 (void **) &pSMBr);
5948 if (rc)
5949 return rc;
5950
5951 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5952 name_len =
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005953 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06005954 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005955 name_len++; /* trailing null */
5956 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005957 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005958 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005959 name_len++; /* trailing null */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005960 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005961 }
5962
5963 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005964 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005965 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005966 /* BB find max SMB PDU from sess structure BB */
5967 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005968 pSMB->MaxSetupCount = 0;
5969 pSMB->Reserved = 0;
5970 pSMB->Flags = 0;
5971 pSMB->Timeout = 0;
5972 pSMB->Reserved2 = 0;
5973 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005974 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005975 offset = param_offset + params;
5976 data_offset =
5977 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5978 offset);
5979 memset(data_offset, 0, count);
5980 pSMB->DataOffset = cpu_to_le16(offset);
5981 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5982 pSMB->SetupCount = 1;
5983 pSMB->Reserved3 = 0;
5984 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5985 byte_count = 3 /* pad */ + params + count;
5986 pSMB->ParameterCount = cpu_to_le16(params);
5987 pSMB->DataCount = cpu_to_le16(count);
5988 pSMB->TotalParameterCount = pSMB->ParameterCount;
5989 pSMB->TotalDataCount = pSMB->DataCount;
5990 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5991 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005992 inc_rfc1001_len(pSMB, byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005993
Jeff Layton654cf142009-07-09 20:02:49 -04005994 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005995
5996 pSMB->ByteCount = cpu_to_le16(byte_count);
5997 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5998 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005999 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00006000 cFYI(1, "SetPathInfo (perms) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006001
Steve French0d817bc2008-05-22 02:02:03 +00006002 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006003 if (rc == -EAGAIN)
6004 goto setPermsRetry;
6005 return rc;
6006}
6007
Linus Torvalds1da177e2005-04-16 15:20:36 -07006008#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05006009/*
6010 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
6011 * function used by listxattr and getxattr type calls. When ea_name is set,
6012 * it looks for that attribute name and stuffs that value into the EAData
6013 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
6014 * buffer. In both cases, the return value is either the length of the
6015 * resulting data or a negative error code. If EAData is a NULL pointer then
6016 * the data isn't copied to it, but the length is returned.
6017 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006018ssize_t
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006019CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05006020 const unsigned char *searchName, const unsigned char *ea_name,
6021 char *EAData, size_t buf_size,
6022 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006023{
6024 /* BB assumes one setup word */
6025 TRANSACTION2_QPI_REQ *pSMB = NULL;
6026 TRANSACTION2_QPI_RSP *pSMBr = NULL;
6027 int rc = 0;
6028 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05006029 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006030 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00006031 struct fea *temp_fea;
6032 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006033 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006034 __u16 params, byte_count, data_offset;
Jeff Layton5980fc92011-07-28 12:48:26 -04006035 unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006036
Joe Perchesb6b38f72010-04-21 03:50:45 +00006037 cFYI(1, "In Query All EAs path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006038QAllEAsRetry:
6039 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6040 (void **) &pSMBr);
6041 if (rc)
6042 return rc;
6043
6044 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05006045 list_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006046 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
6047 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05006048 list_len++; /* trailing null */
6049 list_len *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006050 } else { /* BB improve the check for buffer overruns BB */
Jeff Layton6e462b92010-02-10 16:18:26 -05006051 list_len = strnlen(searchName, PATH_MAX);
6052 list_len++; /* trailing null */
6053 strncpy(pSMB->FileName, searchName, list_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006054 }
6055
Jeff Layton6e462b92010-02-10 16:18:26 -05006056 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006057 pSMB->TotalDataCount = 0;
6058 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006059 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05006060 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006061 pSMB->MaxSetupCount = 0;
6062 pSMB->Reserved = 0;
6063 pSMB->Flags = 0;
6064 pSMB->Timeout = 0;
6065 pSMB->Reserved2 = 0;
6066 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00006067 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006068 pSMB->DataCount = 0;
6069 pSMB->DataOffset = 0;
6070 pSMB->SetupCount = 1;
6071 pSMB->Reserved3 = 0;
6072 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
6073 byte_count = params + 1 /* pad */ ;
6074 pSMB->TotalParameterCount = cpu_to_le16(params);
6075 pSMB->ParameterCount = pSMB->TotalParameterCount;
6076 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
6077 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006078 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006079 pSMB->ByteCount = cpu_to_le16(byte_count);
6080
6081 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6082 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6083 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006084 cFYI(1, "Send error in QueryAllEAs = %d", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05006085 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006086 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006087
6088
6089 /* BB also check enough total bytes returned */
6090 /* BB we need to improve the validity checking
6091 of these trans2 responses */
6092
6093 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Jeff Layton820a8032011-05-04 08:05:26 -04006094 if (rc || get_bcc(&pSMBr->hdr) < 4) {
Jeff Laytonf0d38682010-02-10 16:18:26 -05006095 rc = -EIO; /* bad smb */
6096 goto QAllEAsOut;
6097 }
6098
6099 /* check that length of list is not more than bcc */
6100 /* check that each entry does not go beyond length
6101 of list */
6102 /* check that each element of each entry does not
6103 go beyond end of list */
6104 /* validate_trans2_offsets() */
6105 /* BB check if start of smb + data_offset > &bcc+ bcc */
6106
6107 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
6108 ea_response_data = (struct fealist *)
6109 (((char *) &pSMBr->hdr.Protocol) + data_offset);
6110
Jeff Layton6e462b92010-02-10 16:18:26 -05006111 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesb6b38f72010-04-21 03:50:45 +00006112 cFYI(1, "ea length %d", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05006113 if (list_len <= 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006114 cFYI(1, "empty EA list returned from server");
Jeff Laytonf0d38682010-02-10 16:18:26 -05006115 goto QAllEAsOut;
6116 }
6117
Jeff Layton0cd126b2010-02-10 16:18:26 -05006118 /* make sure list_len doesn't go past end of SMB */
Jeff Layton690c5222011-01-20 13:36:51 -05006119 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
Jeff Layton0cd126b2010-02-10 16:18:26 -05006120 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006121 cFYI(1, "EA list appears to go beyond SMB");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006122 rc = -EIO;
6123 goto QAllEAsOut;
6124 }
6125
Jeff Laytonf0d38682010-02-10 16:18:26 -05006126 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05006127 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006128 temp_fea = ea_response_data->list;
6129 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05006130 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00006131 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006132 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006133
Jeff Layton6e462b92010-02-10 16:18:26 -05006134 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006135 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006136 /* make sure we can read name_len and value_len */
6137 if (list_len < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006138 cFYI(1, "EA entry goes beyond length of list");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006139 rc = -EIO;
6140 goto QAllEAsOut;
6141 }
6142
6143 name_len = temp_fea->name_len;
6144 value_len = le16_to_cpu(temp_fea->value_len);
6145 list_len -= name_len + 1 + value_len;
6146 if (list_len < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006147 cFYI(1, "EA entry goes beyond length of list");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006148 rc = -EIO;
6149 goto QAllEAsOut;
6150 }
6151
Jeff Layton31c05192010-02-10 16:18:26 -05006152 if (ea_name) {
Jeff Layton91d065c2011-07-26 18:23:47 -04006153 if (ea_name_len == name_len &&
Jeff Laytonac423442011-10-11 06:41:32 -04006154 memcmp(ea_name, temp_ptr, name_len) == 0) {
Jeff Layton31c05192010-02-10 16:18:26 -05006155 temp_ptr += name_len + 1;
6156 rc = value_len;
6157 if (buf_size == 0)
6158 goto QAllEAsOut;
6159 if ((size_t)value_len > buf_size) {
6160 rc = -ERANGE;
6161 goto QAllEAsOut;
6162 }
6163 memcpy(EAData, temp_ptr, value_len);
6164 goto QAllEAsOut;
6165 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006166 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05006167 /* account for prefix user. and trailing null */
6168 rc += (5 + 1 + name_len);
6169 if (rc < (int) buf_size) {
6170 memcpy(EAData, "user.", 5);
6171 EAData += 5;
6172 memcpy(EAData, temp_ptr, name_len);
6173 EAData += name_len;
6174 /* null terminate name */
6175 *EAData = 0;
6176 ++EAData;
6177 } else if (buf_size == 0) {
6178 /* skip copy - calc size only */
6179 } else {
6180 /* stop before overrun buffer */
6181 rc = -ERANGE;
6182 break;
6183 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006184 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05006185 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006186 temp_fea = (struct fea *)temp_ptr;
6187 }
6188
Jeff Layton31c05192010-02-10 16:18:26 -05006189 /* didn't find the named attribute */
6190 if (ea_name)
6191 rc = -ENODATA;
6192
Jeff Laytonf0d38682010-02-10 16:18:26 -05006193QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00006194 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006195 if (rc == -EAGAIN)
6196 goto QAllEAsRetry;
6197
6198 return (ssize_t)rc;
6199}
6200
Linus Torvalds1da177e2005-04-16 15:20:36 -07006201int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006202CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
6203 const char *fileName, const char *ea_name, const void *ea_value,
Steve French50c2f752007-07-13 00:33:32 +00006204 const __u16 ea_value_len, const struct nls_table *nls_codepage,
6205 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006206{
6207 struct smb_com_transaction2_spi_req *pSMB = NULL;
6208 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
6209 struct fealist *parm_data;
6210 int name_len;
6211 int rc = 0;
6212 int bytes_returned = 0;
6213 __u16 params, param_offset, byte_count, offset, count;
6214
Joe Perchesb6b38f72010-04-21 03:50:45 +00006215 cFYI(1, "In SetEA");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006216SetEARetry:
6217 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6218 (void **) &pSMBr);
6219 if (rc)
6220 return rc;
6221
6222 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6223 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006224 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
6225 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006226 name_len++; /* trailing null */
6227 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00006228 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006229 name_len = strnlen(fileName, PATH_MAX);
6230 name_len++; /* trailing null */
6231 strncpy(pSMB->FileName, fileName, name_len);
6232 }
6233
6234 params = 6 + name_len;
6235
6236 /* done calculating parms using name_len of file name,
6237 now use name_len to calculate length of ea name
6238 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00006239 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006240 name_len = 0;
6241 else
Steve French50c2f752007-07-13 00:33:32 +00006242 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006243
Steve Frenchdae5dbd2007-12-30 23:49:57 +00006244 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006245 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006246 /* BB find max SMB PDU from sess */
6247 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006248 pSMB->MaxSetupCount = 0;
6249 pSMB->Reserved = 0;
6250 pSMB->Flags = 0;
6251 pSMB->Timeout = 0;
6252 pSMB->Reserved2 = 0;
6253 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006254 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006255 offset = param_offset + params;
6256 pSMB->InformationLevel =
6257 cpu_to_le16(SMB_SET_FILE_EA);
6258
6259 parm_data =
6260 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
6261 offset);
6262 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6263 pSMB->DataOffset = cpu_to_le16(offset);
6264 pSMB->SetupCount = 1;
6265 pSMB->Reserved3 = 0;
6266 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6267 byte_count = 3 /* pad */ + params + count;
6268 pSMB->DataCount = cpu_to_le16(count);
6269 parm_data->list_len = cpu_to_le32(count);
6270 parm_data->list[0].EA_flags = 0;
6271 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08006272 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006273 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00006274 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00006275 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006276 parm_data->list[0].name[name_len] = 0;
6277 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
6278 /* caller ensures that ea_value_len is less than 64K but
6279 we need to ensure that it fits within the smb */
6280
Steve French50c2f752007-07-13 00:33:32 +00006281 /*BB add length check to see if it would fit in
6282 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00006283 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
6284 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00006285 memcpy(parm_data->list[0].name+name_len+1,
6286 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006287
6288 pSMB->TotalDataCount = pSMB->DataCount;
6289 pSMB->ParameterCount = cpu_to_le16(params);
6290 pSMB->TotalParameterCount = pSMB->ParameterCount;
6291 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006292 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006293 pSMB->ByteCount = cpu_to_le16(byte_count);
6294 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6295 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006296 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00006297 cFYI(1, "SetPathInfo (EA) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006298
6299 cifs_buf_release(pSMB);
6300
6301 if (rc == -EAGAIN)
6302 goto SetEARetry;
6303
6304 return rc;
6305}
Linus Torvalds1da177e2005-04-16 15:20:36 -07006306#endif
Steve French0eff0e22011-02-24 05:39:23 +00006307
6308#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */
6309/*
6310 * Years ago the kernel added a "dnotify" function for Samba server,
6311 * to allow network clients (such as Windows) to display updated
6312 * lists of files in directory listings automatically when
6313 * files are added by one user when another user has the
6314 * same directory open on their desktop. The Linux cifs kernel
6315 * client hooked into the kernel side of this interface for
6316 * the same reason, but ironically when the VFS moved from
6317 * "dnotify" to "inotify" it became harder to plug in Linux
6318 * network file system clients (the most obvious use case
6319 * for notify interfaces is when multiple users can update
6320 * the contents of the same directory - exactly what network
6321 * file systems can do) although the server (Samba) could
6322 * still use it. For the short term we leave the worker
6323 * function ifdeffed out (below) until inotify is fixed
6324 * in the VFS to make it easier to plug in network file
6325 * system clients. If inotify turns out to be permanently
6326 * incompatible for network fs clients, we could instead simply
6327 * expose this config flag by adding a future cifs (and smb2) notify ioctl.
6328 */
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006329int CIFSSMBNotify(const unsigned int xid, struct cifs_tcon *tcon,
Steve French0eff0e22011-02-24 05:39:23 +00006330 const int notify_subdirs, const __u16 netfid,
6331 __u32 filter, struct file *pfile, int multishot,
6332 const struct nls_table *nls_codepage)
6333{
6334 int rc = 0;
6335 struct smb_com_transaction_change_notify_req *pSMB = NULL;
6336 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
6337 struct dir_notify_req *dnotify_req;
6338 int bytes_returned;
6339
6340 cFYI(1, "In CIFSSMBNotify for file handle %d", (int)netfid);
6341 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
6342 (void **) &pSMBr);
6343 if (rc)
6344 return rc;
6345
6346 pSMB->TotalParameterCount = 0 ;
6347 pSMB->TotalDataCount = 0;
6348 pSMB->MaxParameterCount = cpu_to_le32(2);
Jeff Laytonc974bef2011-10-11 06:41:32 -04006349 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Steve French0eff0e22011-02-24 05:39:23 +00006350 pSMB->MaxSetupCount = 4;
6351 pSMB->Reserved = 0;
6352 pSMB->ParameterOffset = 0;
6353 pSMB->DataCount = 0;
6354 pSMB->DataOffset = 0;
6355 pSMB->SetupCount = 4; /* single byte does not need le conversion */
6356 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
6357 pSMB->ParameterCount = pSMB->TotalParameterCount;
6358 if (notify_subdirs)
6359 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
6360 pSMB->Reserved2 = 0;
6361 pSMB->CompletionFilter = cpu_to_le32(filter);
6362 pSMB->Fid = netfid; /* file handle always le */
6363 pSMB->ByteCount = 0;
6364
6365 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6366 (struct smb_hdr *)pSMBr, &bytes_returned,
6367 CIFS_ASYNC_OP);
6368 if (rc) {
6369 cFYI(1, "Error in Notify = %d", rc);
6370 } else {
6371 /* Add file to outstanding requests */
6372 /* BB change to kmem cache alloc */
6373 dnotify_req = kmalloc(
6374 sizeof(struct dir_notify_req),
6375 GFP_KERNEL);
6376 if (dnotify_req) {
6377 dnotify_req->Pid = pSMB->hdr.Pid;
6378 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
6379 dnotify_req->Mid = pSMB->hdr.Mid;
6380 dnotify_req->Tid = pSMB->hdr.Tid;
6381 dnotify_req->Uid = pSMB->hdr.Uid;
6382 dnotify_req->netfid = netfid;
6383 dnotify_req->pfile = pfile;
6384 dnotify_req->filter = filter;
6385 dnotify_req->multishot = multishot;
6386 spin_lock(&GlobalMid_Lock);
6387 list_add_tail(&dnotify_req->lhead,
6388 &GlobalDnotifyReqList);
6389 spin_unlock(&GlobalMid_Lock);
6390 } else
6391 rc = -ENOMEM;
6392 }
6393 cifs_buf_release(pSMB);
6394 return rc;
6395}
6396#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */