blob: 88bbb3ef95b35ea2d3ba3d1cde66a4bd64a9e089 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/cifssmb.c
3 *
Steve Frenchf19159d2010-04-21 04:12:10 +00004 * Copyright (C) International Business Machines Corp., 2002,2010
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * Author(s): Steve French (sfrench@us.ibm.com)
6 *
7 * Contains the routines for constructing the SMB PDUs themselves
8 *
9 * This library is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as published
11 * by the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
17 * the GNU Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24 /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c */
25 /* These are mostly routines that operate on a pathname, or on a tree id */
26 /* (mounted volume), but there are eight handle based routines which must be */
Steve French2dd29d32007-04-23 22:07:35 +000027 /* treated slightly differently for reconnection purposes since we never */
28 /* want to reuse a stale file handle and only the caller knows the file info */
Linus Torvalds1da177e2005-04-16 15:20:36 -070029
30#include <linux/fs.h>
31#include <linux/kernel.h>
32#include <linux/vfs.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090033#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include <linux/posix_acl_xattr.h>
Jeff Laytonc28c89f2011-05-19 16:22:56 -040035#include <linux/pagemap.h>
Jeff Laytone28bc5b2011-10-19 15:30:07 -040036#include <linux/swap.h>
37#include <linux/task_io_accounting_ops.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070038#include <asm/uaccess.h>
39#include "cifspdu.h"
40#include "cifsglob.h"
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +000041#include "cifsacl.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070042#include "cifsproto.h"
43#include "cifs_unicode.h"
44#include "cifs_debug.h"
Jeff Laytone28bc5b2011-10-19 15:30:07 -040045#include "fscache.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070046
47#ifdef CONFIG_CIFS_POSIX
48static struct {
49 int index;
50 char *name;
51} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000052#ifdef CONFIG_CIFS_WEAK_PW_HASH
53 {LANMAN_PROT, "\2LM1.2X002"},
Steve French9ac00b72006-09-30 04:13:17 +000054 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000055#endif /* weak password hashing for legacy clients */
Steve French50c2f752007-07-13 00:33:32 +000056 {CIFS_PROT, "\2NT LM 0.12"},
Steve French39798772006-05-31 22:40:51 +000057 {POSIX_PROT, "\2POSIX 2"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070058 {BAD_PROT, "\2"}
59};
60#else
61static struct {
62 int index;
63 char *name;
64} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000065#ifdef CONFIG_CIFS_WEAK_PW_HASH
66 {LANMAN_PROT, "\2LM1.2X002"},
Steve French18f75ca2006-10-01 03:13:01 +000067 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000068#endif /* weak password hashing for legacy clients */
Steve French790fe572007-07-07 19:25:05 +000069 {CIFS_PROT, "\2NT LM 0.12"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070070 {BAD_PROT, "\2"}
71};
72#endif
73
Steve French39798772006-05-31 22:40:51 +000074/* define the number of elements in the cifs dialect array */
75#ifdef CONFIG_CIFS_POSIX
76#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000077#define CIFS_NUM_PROT 4
Steve French39798772006-05-31 22:40:51 +000078#else
79#define CIFS_NUM_PROT 2
80#endif /* CIFS_WEAK_PW_HASH */
81#else /* not posix */
82#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000083#define CIFS_NUM_PROT 3
Steve French39798772006-05-31 22:40:51 +000084#else
85#define CIFS_NUM_PROT 1
86#endif /* CONFIG_CIFS_WEAK_PW_HASH */
87#endif /* CIFS_POSIX */
88
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +040089/*
90 * Mark as invalid, all open files on tree connections since they
91 * were closed when session to server was lost.
92 */
93void
94cifs_mark_open_files_invalid(struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -070095{
96 struct cifsFileInfo *open_file = NULL;
Steve French790fe572007-07-07 19:25:05 +000097 struct list_head *tmp;
98 struct list_head *tmp1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070099
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400100 /* list all files open on tree connection and mark them invalid */
Jeff Layton44772882010-10-15 15:34:03 -0400101 spin_lock(&cifs_file_list_lock);
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400102 list_for_each_safe(tmp, tmp1, &tcon->openFileList) {
Steve French790fe572007-07-07 19:25:05 +0000103 open_file = list_entry(tmp, struct cifsFileInfo, tlist);
Steve Frenchad8b15f2008-08-08 21:10:16 +0000104 open_file->invalidHandle = true;
Jeff Layton3bc303c2009-09-21 06:47:50 -0400105 open_file->oplock_break_cancelled = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106 }
Jeff Layton44772882010-10-15 15:34:03 -0400107 spin_unlock(&cifs_file_list_lock);
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400108 /*
109 * BB Add call to invalidate_inodes(sb) for all superblocks mounted
110 * to this tcon.
111 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112}
113
Jeff Layton9162ab22009-09-03 12:07:17 -0400114/* reconnect the socket, tcon, and smb session if needed */
115static int
Steve French96daf2b2011-05-27 04:34:02 +0000116cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
Jeff Layton9162ab22009-09-03 12:07:17 -0400117{
Jeff Laytonc4a55342011-07-28 12:40:36 -0400118 int rc;
Steve French96daf2b2011-05-27 04:34:02 +0000119 struct cifs_ses *ses;
Jeff Layton9162ab22009-09-03 12:07:17 -0400120 struct TCP_Server_Info *server;
121 struct nls_table *nls_codepage;
122
123 /*
124 * SMBs NegProt, SessSetup, uLogoff do not have tcon yet so check for
125 * tcp and smb session status done differently for those three - in the
126 * calling routine
127 */
128 if (!tcon)
129 return 0;
130
131 ses = tcon->ses;
132 server = ses->server;
133
134 /*
135 * only tree disconnect, open, and write, (and ulogoff which does not
136 * have tcon) are allowed as we start force umount
137 */
138 if (tcon->tidStatus == CifsExiting) {
139 if (smb_command != SMB_COM_WRITE_ANDX &&
140 smb_command != SMB_COM_OPEN_ANDX &&
141 smb_command != SMB_COM_TREE_DISCONNECT) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000142 cFYI(1, "can not send cmd %d while umounting",
143 smb_command);
Jeff Layton9162ab22009-09-03 12:07:17 -0400144 return -ENODEV;
145 }
146 }
147
Jeff Layton9162ab22009-09-03 12:07:17 -0400148 /*
149 * Give demultiplex thread up to 10 seconds to reconnect, should be
150 * greater than cifs socket timeout which is 7 seconds
151 */
152 while (server->tcpStatus == CifsNeedReconnect) {
153 wait_event_interruptible_timeout(server->response_q,
Steve Frenchfd88ce92011-04-12 01:01:14 +0000154 (server->tcpStatus != CifsNeedReconnect), 10 * HZ);
Jeff Layton9162ab22009-09-03 12:07:17 -0400155
Steve Frenchfd88ce92011-04-12 01:01:14 +0000156 /* are we still trying to reconnect? */
Jeff Layton9162ab22009-09-03 12:07:17 -0400157 if (server->tcpStatus != CifsNeedReconnect)
158 break;
159
160 /*
161 * on "soft" mounts we wait once. Hard mounts keep
162 * retrying until process is killed or server comes
163 * back on-line
164 */
Jeff Laytond4025392011-02-07 08:54:35 -0500165 if (!tcon->retry) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000166 cFYI(1, "gave up waiting on reconnect in smb_init");
Jeff Layton9162ab22009-09-03 12:07:17 -0400167 return -EHOSTDOWN;
168 }
169 }
170
171 if (!ses->need_reconnect && !tcon->need_reconnect)
172 return 0;
173
174 nls_codepage = load_nls_default();
175
176 /*
177 * need to prevent multiple threads trying to simultaneously
178 * reconnect the same SMB session
179 */
Steve Frenchd7b619c2010-02-25 05:36:46 +0000180 mutex_lock(&ses->session_mutex);
Jeff Layton198b5682010-04-24 07:57:48 -0400181 rc = cifs_negotiate_protocol(0, ses);
182 if (rc == 0 && ses->need_reconnect)
Jeff Layton9162ab22009-09-03 12:07:17 -0400183 rc = cifs_setup_session(0, ses, nls_codepage);
184
185 /* do we need to reconnect tcon? */
186 if (rc || !tcon->need_reconnect) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000187 mutex_unlock(&ses->session_mutex);
Jeff Layton9162ab22009-09-03 12:07:17 -0400188 goto out;
189 }
190
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400191 cifs_mark_open_files_invalid(tcon);
Jeff Layton9162ab22009-09-03 12:07:17 -0400192 rc = CIFSTCon(0, ses, tcon->treeName, tcon, nls_codepage);
Steve Frenchd7b619c2010-02-25 05:36:46 +0000193 mutex_unlock(&ses->session_mutex);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000194 cFYI(1, "reconnect tcon rc = %d", rc);
Jeff Layton9162ab22009-09-03 12:07:17 -0400195
196 if (rc)
197 goto out;
198
199 /*
200 * FIXME: check if wsize needs updated due to negotiated smb buffer
201 * size shrinking
202 */
203 atomic_inc(&tconInfoReconnectCount);
204
205 /* tell server Unix caps we support */
206 if (ses->capabilities & CAP_UNIX)
207 reset_cifs_unix_caps(0, tcon, NULL, NULL);
208
209 /*
210 * Removed call to reopen open files here. It is safer (and faster) to
211 * reopen files one at a time as needed in read and write.
212 *
213 * FIXME: what about file locks? don't we need to reclaim them ASAP?
214 */
215
216out:
217 /*
218 * Check if handle based operation so we know whether we can continue
219 * or not without returning to caller to reset file handle
220 */
221 switch (smb_command) {
222 case SMB_COM_READ_ANDX:
223 case SMB_COM_WRITE_ANDX:
224 case SMB_COM_CLOSE:
225 case SMB_COM_FIND_CLOSE2:
226 case SMB_COM_LOCKING_ANDX:
227 rc = -EAGAIN;
228 }
229
230 unload_nls(nls_codepage);
231 return rc;
232}
233
Steve Frenchad7a2922008-02-07 23:25:02 +0000234/* Allocate and return pointer to an SMB request buffer, and set basic
235 SMB information in the SMB header. If the return code is zero, this
236 function must have filled in request_buf pointer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237static int
Steve French96daf2b2011-05-27 04:34:02 +0000238small_smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000239 void **request_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240{
Jeff Laytonf5695992010-09-29 15:27:08 -0400241 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242
Jeff Layton9162ab22009-09-03 12:07:17 -0400243 rc = cifs_reconnect_tcon(tcon, smb_command);
Steve French790fe572007-07-07 19:25:05 +0000244 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245 return rc;
246
247 *request_buf = cifs_small_buf_get();
248 if (*request_buf == NULL) {
249 /* BB should we add a retry in here if not a writepage? */
250 return -ENOMEM;
251 }
252
Steve French63135e02007-07-17 17:34:02 +0000253 header_assemble((struct smb_hdr *) *request_buf, smb_command,
Steve Frenchc18c8422007-07-18 23:21:09 +0000254 tcon, wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255
Steve French790fe572007-07-07 19:25:05 +0000256 if (tcon != NULL)
257 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha45443472005-08-24 13:59:35 -0700258
Jeff Laytonf5695992010-09-29 15:27:08 -0400259 return 0;
Steve French5815449d2006-02-14 01:36:20 +0000260}
261
Steve French12b3b8f2006-02-09 21:12:47 +0000262int
Steve French50c2f752007-07-13 00:33:32 +0000263small_smb_init_no_tc(const int smb_command, const int wct,
Steve French96daf2b2011-05-27 04:34:02 +0000264 struct cifs_ses *ses, void **request_buf)
Steve French12b3b8f2006-02-09 21:12:47 +0000265{
266 int rc;
Steve French50c2f752007-07-13 00:33:32 +0000267 struct smb_hdr *buffer;
Steve French12b3b8f2006-02-09 21:12:47 +0000268
Steve French5815449d2006-02-14 01:36:20 +0000269 rc = small_smb_init(smb_command, wct, NULL, request_buf);
Steve French790fe572007-07-07 19:25:05 +0000270 if (rc)
Steve French12b3b8f2006-02-09 21:12:47 +0000271 return rc;
272
Steve French04fdabe2006-02-10 05:52:50 +0000273 buffer = (struct smb_hdr *)*request_buf;
Pavel Shilovsky88257362012-05-23 14:01:59 +0400274 buffer->Mid = get_next_mid(ses->server);
Steve French12b3b8f2006-02-09 21:12:47 +0000275 if (ses->capabilities & CAP_UNICODE)
276 buffer->Flags2 |= SMBFLG2_UNICODE;
Steve French04fdabe2006-02-10 05:52:50 +0000277 if (ses->capabilities & CAP_STATUS32)
Steve French12b3b8f2006-02-09 21:12:47 +0000278 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
279
280 /* uid, tid can stay at zero as set in header assemble */
281
Steve French50c2f752007-07-13 00:33:32 +0000282 /* BB add support for turning on the signing when
Steve French12b3b8f2006-02-09 21:12:47 +0000283 this function is used after 1st of session setup requests */
284
285 return rc;
286}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287
288/* If the return code is zero, this function must fill in request_buf pointer */
289static int
Steve French96daf2b2011-05-27 04:34:02 +0000290__smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400291 void **request_buf, void **response_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293 *request_buf = cifs_buf_get();
294 if (*request_buf == NULL) {
295 /* BB should we add a retry in here if not a writepage? */
296 return -ENOMEM;
297 }
298 /* Although the original thought was we needed the response buf for */
299 /* potential retries of smb operations it turns out we can determine */
300 /* from the mid flags when the request buffer can be resent without */
301 /* having to use a second distinct buffer for the response */
Steve French790fe572007-07-07 19:25:05 +0000302 if (response_buf)
Steve French50c2f752007-07-13 00:33:32 +0000303 *response_buf = *request_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304
305 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000306 wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307
Steve French790fe572007-07-07 19:25:05 +0000308 if (tcon != NULL)
309 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha45443472005-08-24 13:59:35 -0700310
Jeff Laytonf5695992010-09-29 15:27:08 -0400311 return 0;
312}
313
314/* If the return code is zero, this function must fill in request_buf pointer */
315static int
Steve French96daf2b2011-05-27 04:34:02 +0000316smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400317 void **request_buf, void **response_buf)
318{
319 int rc;
320
321 rc = cifs_reconnect_tcon(tcon, smb_command);
322 if (rc)
323 return rc;
324
325 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
326}
327
328static int
Steve French96daf2b2011-05-27 04:34:02 +0000329smb_init_no_reconnect(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400330 void **request_buf, void **response_buf)
331{
332 if (tcon->ses->need_reconnect || tcon->need_reconnect)
333 return -EHOSTDOWN;
334
335 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336}
337
Steve French50c2f752007-07-13 00:33:32 +0000338static int validate_t2(struct smb_t2_rsp *pSMB)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339{
Jeff Layton12df83c2011-01-20 13:36:51 -0500340 unsigned int total_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341
Jeff Layton12df83c2011-01-20 13:36:51 -0500342 /* check for plausible wct */
343 if (pSMB->hdr.WordCount < 10)
344 goto vt2_err;
345
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346 /* check for parm and data offset going beyond end of smb */
Jeff Layton12df83c2011-01-20 13:36:51 -0500347 if (get_unaligned_le16(&pSMB->t2_rsp.ParameterOffset) > 1024 ||
348 get_unaligned_le16(&pSMB->t2_rsp.DataOffset) > 1024)
349 goto vt2_err;
350
Jeff Layton12df83c2011-01-20 13:36:51 -0500351 total_size = get_unaligned_le16(&pSMB->t2_rsp.ParameterCount);
352 if (total_size >= 512)
353 goto vt2_err;
354
Jeff Laytonfd5707e2011-03-31 17:22:07 -0400355 /* check that bcc is at least as big as parms + data, and that it is
356 * less than negotiated smb buffer
357 */
Jeff Layton12df83c2011-01-20 13:36:51 -0500358 total_size += get_unaligned_le16(&pSMB->t2_rsp.DataCount);
359 if (total_size > get_bcc(&pSMB->hdr) ||
360 total_size >= CIFSMaxBufSize + MAX_CIFS_HDR_SIZE)
361 goto vt2_err;
362
363 return 0;
364vt2_err:
Steve French50c2f752007-07-13 00:33:32 +0000365 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 sizeof(struct smb_t2_rsp) + 16);
Jeff Layton12df83c2011-01-20 13:36:51 -0500367 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368}
Jeff Layton690c5222011-01-20 13:36:51 -0500369
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370int
Pavel Shilovsky286170a2012-05-25 10:43:58 +0400371CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372{
373 NEGOTIATE_REQ *pSMB;
374 NEGOTIATE_RSP *pSMBr;
375 int rc = 0;
376 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000377 int i;
Steve French50c2f752007-07-13 00:33:32 +0000378 struct TCP_Server_Info *server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 u16 count;
Steve French750d1152006-06-27 06:28:30 +0000380 unsigned int secFlags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381
Steve French790fe572007-07-07 19:25:05 +0000382 if (ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 server = ses->server;
384 else {
385 rc = -EIO;
386 return rc;
387 }
388 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
389 (void **) &pSMB, (void **) &pSMBr);
390 if (rc)
391 return rc;
Steve French750d1152006-06-27 06:28:30 +0000392
393 /* if any of auth flags (ie not sign or seal) are overriden use them */
Steve French790fe572007-07-07 19:25:05 +0000394 if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
Steve French762e5ab2007-06-28 18:41:42 +0000395 secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
Steve French750d1152006-06-27 06:28:30 +0000396 else /* if override flags set only sign/seal OR them with global auth */
Jeff Layton04912d62010-04-24 07:57:45 -0400397 secFlags = global_secflags | ses->overrideSecFlg;
Steve French750d1152006-06-27 06:28:30 +0000398
Joe Perchesb6b38f72010-04-21 03:50:45 +0000399 cFYI(1, "secFlags 0x%x", secFlags);
Steve Frenchf40c5622006-06-28 00:13:38 +0000400
Pavel Shilovsky88257362012-05-23 14:01:59 +0400401 pSMB->hdr.Mid = get_next_mid(server);
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000402 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
Steve Frencha0136892007-10-04 20:05:09 +0000403
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000404 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
Steve French254e55e2006-06-04 05:53:15 +0000405 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Steve Frencha0136892007-10-04 20:05:09 +0000406 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000407 cFYI(1, "Kerberos only mechanism, enable extended security");
Steve Frencha0136892007-10-04 20:05:09 +0000408 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Jeff Laytonb4d6fcf2011-01-07 11:30:28 -0500409 } else if ((secFlags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP)
Steve Frenchac683922009-05-06 04:16:04 +0000410 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
411 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_NTLMSSP) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000412 cFYI(1, "NTLMSSP only mechanism, enable extended security");
Steve Frenchac683922009-05-06 04:16:04 +0000413 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
414 }
Steve French50c2f752007-07-13 00:33:32 +0000415
Steve French39798772006-05-31 22:40:51 +0000416 count = 0;
Steve French50c2f752007-07-13 00:33:32 +0000417 for (i = 0; i < CIFS_NUM_PROT; i++) {
Steve French39798772006-05-31 22:40:51 +0000418 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
419 count += strlen(protocols[i].name) + 1;
420 /* null at end of source and target buffers anyway */
421 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000422 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 pSMB->ByteCount = cpu_to_le16(count);
424
425 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
426 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French50c2f752007-07-13 00:33:32 +0000427 if (rc != 0)
Steve French254e55e2006-06-04 05:53:15 +0000428 goto neg_err_exit;
429
Jeff Layton9bf67e52010-04-24 07:57:46 -0400430 server->dialect = le16_to_cpu(pSMBr->DialectIndex);
431 cFYI(1, "Dialect: %d", server->dialect);
Steve French254e55e2006-06-04 05:53:15 +0000432 /* Check wct = 1 error case */
Jeff Layton9bf67e52010-04-24 07:57:46 -0400433 if ((pSMBr->hdr.WordCount < 13) || (server->dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000434 /* core returns wct = 1, but we do not ask for core - otherwise
Steve French50c2f752007-07-13 00:33:32 +0000435 small wct just comes when dialect index is -1 indicating we
Steve French254e55e2006-06-04 05:53:15 +0000436 could not negotiate a common dialect */
437 rc = -EOPNOTSUPP;
438 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000439#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French790fe572007-07-07 19:25:05 +0000440 } else if ((pSMBr->hdr.WordCount == 13)
Jeff Layton9bf67e52010-04-24 07:57:46 -0400441 && ((server->dialect == LANMAN_PROT)
442 || (server->dialect == LANMAN2_PROT))) {
Steve Frenchb815f1e52006-10-02 05:53:29 +0000443 __s16 tmp;
Steve French50c2f752007-07-13 00:33:32 +0000444 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
Steve French254e55e2006-06-04 05:53:15 +0000445
Steve French790fe572007-07-07 19:25:05 +0000446 if ((secFlags & CIFSSEC_MAY_LANMAN) ||
Steve French750d1152006-06-27 06:28:30 +0000447 (secFlags & CIFSSEC_MAY_PLNTXT))
Steve French254e55e2006-06-04 05:53:15 +0000448 server->secType = LANMAN;
449 else {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000450 cERROR(1, "mount failed weak security disabled"
451 " in /proc/fs/cifs/SecurityFlags");
Steve French39798772006-05-31 22:40:51 +0000452 rc = -EOPNOTSUPP;
453 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000454 }
Pavel Shilovsky286170a2012-05-25 10:43:58 +0400455 server->sec_mode = le16_to_cpu(rsp->SecurityMode);
Pavel Shilovsky10b9b982012-03-20 12:55:09 +0300456 server->maxReq = min_t(unsigned int,
457 le16_to_cpu(rsp->MaxMpxCount),
458 cifs_max_pending);
Pavel Shilovsky45275782012-05-17 17:53:29 +0400459 set_credits(server, server->maxReq);
Jeff Laytonc974bef2011-10-11 06:41:32 -0400460 server->maxBuf = le16_to_cpu(rsp->MaxBufSize);
Steve Frencheca6acf2009-02-20 05:43:09 +0000461 server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
Steve French254e55e2006-06-04 05:53:15 +0000462 /* even though we do not use raw we might as well set this
463 accurately, in case we ever find a need for it */
Steve French790fe572007-07-07 19:25:05 +0000464 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
Steve Frencheca6acf2009-02-20 05:43:09 +0000465 server->max_rw = 0xFF00;
Steve French254e55e2006-06-04 05:53:15 +0000466 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
467 } else {
Steve Frencheca6acf2009-02-20 05:43:09 +0000468 server->max_rw = 0;/* do not need to use raw anyway */
Steve French254e55e2006-06-04 05:53:15 +0000469 server->capabilities = CAP_MPX_MODE;
470 }
Steve Frenchb815f1e52006-10-02 05:53:29 +0000471 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
Steve French1a70d652006-10-02 05:59:18 +0000472 if (tmp == -1) {
Steve French25ee4a92006-09-30 00:54:23 +0000473 /* OS/2 often does not set timezone therefore
474 * we must use server time to calc time zone.
Steve Frenchb815f1e52006-10-02 05:53:29 +0000475 * Could deviate slightly from the right zone.
476 * Smallest defined timezone difference is 15 minutes
477 * (i.e. Nepal). Rounding up/down is done to match
478 * this requirement.
Steve French25ee4a92006-09-30 00:54:23 +0000479 */
Steve Frenchb815f1e52006-10-02 05:53:29 +0000480 int val, seconds, remain, result;
Steve French25ee4a92006-09-30 00:54:23 +0000481 struct timespec ts, utc;
482 utc = CURRENT_TIME;
Jeff Laytonc4a2c082009-05-27 09:37:33 -0400483 ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
484 rsp->SrvTime.Time, 0);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000485 cFYI(1, "SrvTime %d sec since 1970 (utc: %d) diff: %d",
Steve French50c2f752007-07-13 00:33:32 +0000486 (int)ts.tv_sec, (int)utc.tv_sec,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000487 (int)(utc.tv_sec - ts.tv_sec));
Steve Frenchb815f1e52006-10-02 05:53:29 +0000488 val = (int)(utc.tv_sec - ts.tv_sec);
Andre Haupt8594c152007-08-30 20:18:41 +0000489 seconds = abs(val);
Steve French947a5062006-10-02 05:55:25 +0000490 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
Steve Frenchb815f1e52006-10-02 05:53:29 +0000491 remain = seconds % MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000492 if (remain >= (MIN_TZ_ADJ / 2))
Steve Frenchb815f1e52006-10-02 05:53:29 +0000493 result += MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000494 if (val < 0)
Steve Frenchad7a2922008-02-07 23:25:02 +0000495 result = -result;
Steve Frenchb815f1e52006-10-02 05:53:29 +0000496 server->timeAdj = result;
Steve French25ee4a92006-09-30 00:54:23 +0000497 } else {
Steve Frenchb815f1e52006-10-02 05:53:29 +0000498 server->timeAdj = (int)tmp;
499 server->timeAdj *= 60; /* also in seconds */
Steve French25ee4a92006-09-30 00:54:23 +0000500 }
Joe Perchesb6b38f72010-04-21 03:50:45 +0000501 cFYI(1, "server->timeAdj: %d seconds", server->timeAdj);
Steve French25ee4a92006-09-30 00:54:23 +0000502
Steve French39798772006-05-31 22:40:51 +0000503
Steve French254e55e2006-06-04 05:53:15 +0000504 /* BB get server time for time conversions and add
Steve French50c2f752007-07-13 00:33:32 +0000505 code to use it and timezone since this is not UTC */
Steve French39798772006-05-31 22:40:51 +0000506
Steve French50c2f752007-07-13 00:33:32 +0000507 if (rsp->EncryptionKeyLength ==
Steve French25ee4a92006-09-30 00:54:23 +0000508 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500509 memcpy(ses->server->cryptkey, rsp->EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000510 CIFS_CRYPTO_KEY_SIZE);
Steve French96daf2b2011-05-27 04:34:02 +0000511 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
Steve French254e55e2006-06-04 05:53:15 +0000512 rc = -EIO; /* need cryptkey unless plain text */
513 goto neg_err_exit;
514 }
Steve French39798772006-05-31 22:40:51 +0000515
Steve Frenchf19159d2010-04-21 04:12:10 +0000516 cFYI(1, "LANMAN negotiated");
Steve French254e55e2006-06-04 05:53:15 +0000517 /* we will not end up setting signing flags - as no signing
518 was in LANMAN and server did not return the flags on */
519 goto signing_check;
Steve French7c7b25b2006-06-01 19:20:10 +0000520#else /* weak security disabled */
Steve French790fe572007-07-07 19:25:05 +0000521 } else if (pSMBr->hdr.WordCount == 13) {
Steve Frenchf19159d2010-04-21 04:12:10 +0000522 cERROR(1, "mount failed, cifs module not built "
523 "with CIFS_WEAK_PW_HASH support");
Dan Carpenter8212cf72010-03-15 11:22:26 +0300524 rc = -EOPNOTSUPP;
Steve French7c7b25b2006-06-01 19:20:10 +0000525#endif /* WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000526 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000527 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000528 /* unknown wct */
529 rc = -EOPNOTSUPP;
530 goto neg_err_exit;
531 }
532 /* else wct == 17 NTLM */
Steve French96daf2b2011-05-27 04:34:02 +0000533 server->sec_mode = pSMBr->SecurityMode;
534 if ((server->sec_mode & SECMODE_USER) == 0)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000535 cFYI(1, "share mode security");
Steve French39798772006-05-31 22:40:51 +0000536
Steve French96daf2b2011-05-27 04:34:02 +0000537 if ((server->sec_mode & SECMODE_PW_ENCRYPT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000538#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French750d1152006-06-27 06:28:30 +0000539 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000540#endif /* CIFS_WEAK_PW_HASH */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000541 cERROR(1, "Server requests plain text password"
542 " but client support disabled");
Steve French9312f672006-06-04 22:21:07 +0000543
Steve French790fe572007-07-07 19:25:05 +0000544 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
Steve French254e55e2006-06-04 05:53:15 +0000545 server->secType = NTLMv2;
Steve French790fe572007-07-07 19:25:05 +0000546 else if (secFlags & CIFSSEC_MAY_NTLM)
Steve French254e55e2006-06-04 05:53:15 +0000547 server->secType = NTLM;
Steve French790fe572007-07-07 19:25:05 +0000548 else if (secFlags & CIFSSEC_MAY_NTLMV2)
Steve Frenchf40c5622006-06-28 00:13:38 +0000549 server->secType = NTLMv2;
Steve Frencha0136892007-10-04 20:05:09 +0000550 else if (secFlags & CIFSSEC_MAY_KRB5)
551 server->secType = Kerberos;
Steve Frenchac683922009-05-06 04:16:04 +0000552 else if (secFlags & CIFSSEC_MAY_NTLMSSP)
Steve Frenchf46c7232009-06-25 03:04:20 +0000553 server->secType = RawNTLMSSP;
Steve Frencha0136892007-10-04 20:05:09 +0000554 else if (secFlags & CIFSSEC_MAY_LANMAN)
555 server->secType = LANMAN;
Steve Frencha0136892007-10-04 20:05:09 +0000556 else {
557 rc = -EOPNOTSUPP;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000558 cERROR(1, "Invalid security type");
Steve Frencha0136892007-10-04 20:05:09 +0000559 goto neg_err_exit;
560 }
561 /* else ... any others ...? */
Steve French7c7b25b2006-06-01 19:20:10 +0000562
Steve French254e55e2006-06-04 05:53:15 +0000563 /* one byte, so no need to convert this or EncryptionKeyLen from
564 little endian */
Pavel Shilovsky10b9b982012-03-20 12:55:09 +0300565 server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount),
566 cifs_max_pending);
Pavel Shilovsky45275782012-05-17 17:53:29 +0400567 set_credits(server, server->maxReq);
Steve French254e55e2006-06-04 05:53:15 +0000568 /* probably no need to store and check maxvcs */
Jeff Laytonc974bef2011-10-11 06:41:32 -0400569 server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize);
Steve Frencheca6acf2009-02-20 05:43:09 +0000570 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000571 cFYI(DBG2, "Max buf = %d", ses->server->maxBuf);
Steve French254e55e2006-06-04 05:53:15 +0000572 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e52006-10-02 05:53:29 +0000573 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
574 server->timeAdj *= 60;
Steve French254e55e2006-06-04 05:53:15 +0000575 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500576 memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000577 CIFS_CRYPTO_KEY_SIZE);
Steve French07cc6cf2011-05-27 04:12:29 +0000578 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC ||
579 server->capabilities & CAP_EXTENDED_SECURITY) &&
580 (pSMBr->EncryptionKeyLength == 0)) {
Steve French254e55e2006-06-04 05:53:15 +0000581 /* decode security blob */
Jeff Layton820a8032011-05-04 08:05:26 -0400582 count = get_bcc(&pSMBr->hdr);
Jeff Laytone187e442007-10-16 17:10:44 +0000583 if (count < 16) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 rc = -EIO;
Jeff Laytone187e442007-10-16 17:10:44 +0000585 goto neg_err_exit;
586 }
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530587 spin_lock(&cifs_tcp_ses_lock);
Jeff Laytone7ddee92008-11-14 13:44:38 -0500588 if (server->srv_count > 1) {
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530589 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000590 if (memcmp(server->server_GUID,
591 pSMBr->u.extended_response.
592 GUID, 16) != 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000593 cFYI(1, "server UID changed");
Steve French254e55e2006-06-04 05:53:15 +0000594 memcpy(server->server_GUID,
Jeff Laytone187e442007-10-16 17:10:44 +0000595 pSMBr->u.extended_response.GUID,
596 16);
597 }
Jeff Laytone7ddee92008-11-14 13:44:38 -0500598 } else {
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530599 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000600 memcpy(server->server_GUID,
601 pSMBr->u.extended_response.GUID, 16);
Jeff Laytone7ddee92008-11-14 13:44:38 -0500602 }
Jeff Laytone187e442007-10-16 17:10:44 +0000603
604 if (count == 16) {
605 server->secType = RawNTLMSSP;
Steve French254e55e2006-06-04 05:53:15 +0000606 } else {
607 rc = decode_negTokenInit(pSMBr->u.extended_response.
Jeff Layton26efa0b2010-04-24 07:57:49 -0400608 SecurityBlob, count - 16,
609 server);
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000610 if (rc == 1)
Jeff Laytone5459372007-11-03 05:11:06 +0000611 rc = 0;
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000612 else
Steve French254e55e2006-06-04 05:53:15 +0000613 rc = -EINVAL;
Shirish Pargaonkar2b149f12010-09-18 22:02:18 -0500614 if (server->secType == Kerberos) {
615 if (!server->sec_kerberos &&
616 !server->sec_mskerberos)
617 rc = -EOPNOTSUPP;
618 } else if (server->secType == RawNTLMSSP) {
619 if (!server->sec_ntlmssp)
620 rc = -EOPNOTSUPP;
621 } else
622 rc = -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 }
Steve French96daf2b2011-05-27 04:34:02 +0000624 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
Steve French07cc6cf2011-05-27 04:12:29 +0000625 rc = -EIO; /* no crypt key only if plain text pwd */
626 goto neg_err_exit;
Steve French254e55e2006-06-04 05:53:15 +0000627 } else
628 server->capabilities &= ~CAP_EXTENDED_SECURITY;
629
Steve French6344a422006-06-12 04:18:35 +0000630#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French254e55e2006-06-04 05:53:15 +0000631signing_check:
Steve French6344a422006-06-12 04:18:35 +0000632#endif
Steve French762e5ab2007-06-28 18:41:42 +0000633 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
634 /* MUST_SIGN already includes the MAY_SIGN FLAG
635 so if this is zero it means that signing is disabled */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000636 cFYI(1, "Signing disabled");
Steve French96daf2b2011-05-27 04:34:02 +0000637 if (server->sec_mode & SECMODE_SIGN_REQUIRED) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000638 cERROR(1, "Server requires "
Jeff Layton7111d212007-10-16 16:50:25 +0000639 "packet signing to be enabled in "
Joe Perchesb6b38f72010-04-21 03:50:45 +0000640 "/proc/fs/cifs/SecurityFlags.");
Steve Frenchabb63d62007-10-18 02:58:40 +0000641 rc = -EOPNOTSUPP;
642 }
Steve French96daf2b2011-05-27 04:34:02 +0000643 server->sec_mode &=
Steve French254e55e2006-06-04 05:53:15 +0000644 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Steve French762e5ab2007-06-28 18:41:42 +0000645 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
646 /* signing required */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000647 cFYI(1, "Must sign - secFlags 0x%x", secFlags);
Steve French96daf2b2011-05-27 04:34:02 +0000648 if ((server->sec_mode &
Steve French762e5ab2007-06-28 18:41:42 +0000649 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000650 cERROR(1, "signing required but server lacks support");
Jeff38c10a12007-07-06 21:10:07 +0000651 rc = -EOPNOTSUPP;
Steve French762e5ab2007-06-28 18:41:42 +0000652 } else
Steve French96daf2b2011-05-27 04:34:02 +0000653 server->sec_mode |= SECMODE_SIGN_REQUIRED;
Steve French762e5ab2007-06-28 18:41:42 +0000654 } else {
655 /* signing optional ie CIFSSEC_MAY_SIGN */
Steve French96daf2b2011-05-27 04:34:02 +0000656 if ((server->sec_mode & SECMODE_SIGN_REQUIRED) == 0)
657 server->sec_mode &=
Steve French254e55e2006-06-04 05:53:15 +0000658 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 }
Steve French50c2f752007-07-13 00:33:32 +0000660
661neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700662 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000663
Joe Perchesb6b38f72010-04-21 03:50:45 +0000664 cFYI(1, "negprot rc %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 return rc;
666}
667
668int
Pavel Shilovsky2e6e02a2012-05-25 11:11:39 +0400669CIFSSMBTDis(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670{
671 struct smb_hdr *smb_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673
Joe Perchesb6b38f72010-04-21 03:50:45 +0000674 cFYI(1, "In tree disconnect");
Jeff Laytonf1987b42008-11-15 11:12:47 -0500675
676 /* BB: do we need to check this? These should never be NULL. */
677 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
678 return -EIO;
679
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 /*
Jeff Laytonf1987b42008-11-15 11:12:47 -0500681 * No need to return error on this operation if tid invalidated and
682 * closed on server already e.g. due to tcp session crashing. Also,
683 * the tcon is no longer on the list, so no need to take lock before
684 * checking this.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 */
Steve French268875b2009-06-25 00:29:21 +0000686 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
Steve French50c2f752007-07-13 00:33:32 +0000687 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688
Steve French50c2f752007-07-13 00:33:32 +0000689 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700690 (void **)&smb_buffer);
Jeff Laytonf1987b42008-11-15 11:12:47 -0500691 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 return rc;
Steve French133672e2007-11-13 22:41:37 +0000693
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400694 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)smb_buffer, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000696 cFYI(1, "Tree disconnect failed %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697
Steve French50c2f752007-07-13 00:33:32 +0000698 /* No need to return error on this operation if tid invalidated and
Jeff Laytonf1987b42008-11-15 11:12:47 -0500699 closed on server already e.g. due to tcp session crashing */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 if (rc == -EAGAIN)
701 rc = 0;
702
703 return rc;
704}
705
Jeff Layton766fdbb2011-01-11 07:24:21 -0500706/*
707 * This is a no-op for now. We're not really interested in the reply, but
708 * rather in the fact that the server sent one and that server->lstrp
709 * gets updated.
710 *
711 * FIXME: maybe we should consider checking that the reply matches request?
712 */
713static void
714cifs_echo_callback(struct mid_q_entry *mid)
715{
716 struct TCP_Server_Info *server = mid->callback_data;
717
718 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +0400719 add_credits(server, 1, CIFS_ECHO_OP);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500720}
721
722int
723CIFSSMBEcho(struct TCP_Server_Info *server)
724{
725 ECHO_REQ *smb;
726 int rc = 0;
Jeff Laytonfcc31cb2011-05-19 16:22:53 -0400727 struct kvec iov;
Jeff Laytonfec344e2012-09-18 16:20:35 -0700728 struct smb_rqst rqst = { .rq_iov = &iov,
729 .rq_nvec = 1 };
Jeff Layton766fdbb2011-01-11 07:24:21 -0500730
731 cFYI(1, "In echo request");
732
733 rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
734 if (rc)
735 return rc;
736
737 /* set up echo request */
Steve French5443d132011-03-13 05:08:25 +0000738 smb->hdr.Tid = 0xffff;
Jeff Layton99d86c82011-01-20 21:19:25 -0500739 smb->hdr.WordCount = 1;
740 put_unaligned_le16(1, &smb->EchoCount);
Jeff Layton820a8032011-05-04 08:05:26 -0400741 put_bcc(1, &smb->hdr);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500742 smb->Data[0] = 'a';
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000743 inc_rfc1001_len(smb, 3);
Jeff Laytonfcc31cb2011-05-19 16:22:53 -0400744 iov.iov_base = smb;
745 iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
Jeff Layton766fdbb2011-01-11 07:24:21 -0500746
Jeff Laytonfec344e2012-09-18 16:20:35 -0700747 rc = cifs_call_async(server, &rqst, NULL, cifs_echo_callback,
Pavel Shilovskya891f0f2012-05-23 16:14:34 +0400748 server, CIFS_ASYNC_OP | CIFS_ECHO_OP);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500749 if (rc)
750 cFYI(1, "Echo request failed: %d", rc);
751
752 cifs_small_buf_release(smb);
753
754 return rc;
755}
756
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757int
Pavel Shilovsky58c45c52012-05-25 10:54:49 +0400758CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 LOGOFF_ANDX_REQ *pSMB;
761 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762
Joe Perchesb6b38f72010-04-21 03:50:45 +0000763 cFYI(1, "In SMBLogoff for session disconnect");
Jeff Layton14fbf502008-11-14 13:53:46 -0500764
765 /*
766 * BB: do we need to check validity of ses and server? They should
767 * always be valid since we have an active reference. If not, that
768 * should probably be a BUG()
769 */
770 if (!ses || !ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 return -EIO;
772
Steve Frenchd7b619c2010-02-25 05:36:46 +0000773 mutex_lock(&ses->session_mutex);
Steve French3b795212008-11-13 19:45:32 +0000774 if (ses->need_reconnect)
775 goto session_already_dead; /* no need to send SMBlogoff if uid
776 already closed due to reconnect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
778 if (rc) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000779 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 return rc;
781 }
782
Pavel Shilovsky88257362012-05-23 14:01:59 +0400783 pSMB->hdr.Mid = get_next_mid(ses->server);
Steve French1982c342005-08-17 12:38:22 -0700784
Steve French96daf2b2011-05-27 04:34:02 +0000785 if (ses->server->sec_mode &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
787 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788
789 pSMB->hdr.Uid = ses->Suid;
790
791 pSMB->AndXCommand = 0xFF;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400792 rc = SendReceiveNoRsp(xid, ses, (char *) pSMB, 0);
Steve French3b795212008-11-13 19:45:32 +0000793session_already_dead:
Steve Frenchd7b619c2010-02-25 05:36:46 +0000794 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795
796 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000797 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 error */
799 if (rc == -EAGAIN)
800 rc = 0;
801 return rc;
802}
803
804int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400805CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
806 const char *fileName, __u16 type,
807 const struct nls_table *nls_codepage, int remap)
Steve French2d785a52007-07-15 01:48:57 +0000808{
809 TRANSACTION2_SPI_REQ *pSMB = NULL;
810 TRANSACTION2_SPI_RSP *pSMBr = NULL;
811 struct unlink_psx_rq *pRqD;
812 int name_len;
813 int rc = 0;
814 int bytes_returned = 0;
815 __u16 params, param_offset, offset, byte_count;
816
Joe Perchesb6b38f72010-04-21 03:50:45 +0000817 cFYI(1, "In POSIX delete");
Steve French2d785a52007-07-15 01:48:57 +0000818PsxDelete:
819 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
820 (void **) &pSMBr);
821 if (rc)
822 return rc;
823
824 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
825 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -0600826 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
827 PATH_MAX, nls_codepage, remap);
Steve French2d785a52007-07-15 01:48:57 +0000828 name_len++; /* trailing null */
829 name_len *= 2;
830 } else { /* BB add path length overrun check */
831 name_len = strnlen(fileName, PATH_MAX);
832 name_len++; /* trailing null */
833 strncpy(pSMB->FileName, fileName, name_len);
834 }
835
836 params = 6 + name_len;
837 pSMB->MaxParameterCount = cpu_to_le16(2);
838 pSMB->MaxDataCount = 0; /* BB double check this with jra */
839 pSMB->MaxSetupCount = 0;
840 pSMB->Reserved = 0;
841 pSMB->Flags = 0;
842 pSMB->Timeout = 0;
843 pSMB->Reserved2 = 0;
844 param_offset = offsetof(struct smb_com_transaction2_spi_req,
845 InformationLevel) - 4;
846 offset = param_offset + params;
847
848 /* Setup pointer to Request Data (inode type) */
849 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
850 pRqD->type = cpu_to_le16(type);
851 pSMB->ParameterOffset = cpu_to_le16(param_offset);
852 pSMB->DataOffset = cpu_to_le16(offset);
853 pSMB->SetupCount = 1;
854 pSMB->Reserved3 = 0;
855 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
856 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
857
858 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
859 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
860 pSMB->ParameterCount = cpu_to_le16(params);
861 pSMB->TotalParameterCount = pSMB->ParameterCount;
862 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
863 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000864 inc_rfc1001_len(pSMB, byte_count);
Steve French2d785a52007-07-15 01:48:57 +0000865 pSMB->ByteCount = cpu_to_le16(byte_count);
866 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
867 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000868 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000869 cFYI(1, "Posix delete returned %d", rc);
Steve French2d785a52007-07-15 01:48:57 +0000870 cifs_buf_release(pSMB);
871
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400872 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve French2d785a52007-07-15 01:48:57 +0000873
874 if (rc == -EAGAIN)
875 goto PsxDelete;
876
877 return rc;
878}
879
880int
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700881CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
882 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883{
884 DELETE_FILE_REQ *pSMB = NULL;
885 DELETE_FILE_RSP *pSMBr = NULL;
886 int rc = 0;
887 int bytes_returned;
888 int name_len;
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700889 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890
891DelFileRetry:
892 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
893 (void **) &pSMBr);
894 if (rc)
895 return rc;
896
897 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700898 name_len = cifsConvertToUTF16((__le16 *) pSMB->fileName, name,
899 PATH_MAX, cifs_sb->local_nls,
900 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 name_len++; /* trailing null */
902 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700903 } else { /* BB improve check for buffer overruns BB */
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700904 name_len = strnlen(name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 name_len++; /* trailing null */
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700906 strncpy(pSMB->fileName, name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907 }
908 pSMB->SearchAttributes =
909 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
910 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000911 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 pSMB->ByteCount = cpu_to_le16(name_len + 1);
913 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
914 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400915 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000916 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000917 cFYI(1, "Error in RMFile = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918
919 cifs_buf_release(pSMB);
920 if (rc == -EAGAIN)
921 goto DelFileRetry;
922
923 return rc;
924}
925
926int
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400927CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
928 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929{
930 DELETE_DIRECTORY_REQ *pSMB = NULL;
931 DELETE_DIRECTORY_RSP *pSMBr = NULL;
932 int rc = 0;
933 int bytes_returned;
934 int name_len;
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400935 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936
Joe Perchesb6b38f72010-04-21 03:50:45 +0000937 cFYI(1, "In CIFSSMBRmDir");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938RmDirRetry:
939 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
940 (void **) &pSMBr);
941 if (rc)
942 return rc;
943
944 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400945 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
946 PATH_MAX, cifs_sb->local_nls,
947 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948 name_len++; /* trailing null */
949 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700950 } else { /* BB improve check for buffer overruns BB */
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400951 name_len = strnlen(name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952 name_len++; /* trailing null */
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400953 strncpy(pSMB->DirName, name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954 }
955
956 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000957 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958 pSMB->ByteCount = cpu_to_le16(name_len + 1);
959 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
960 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400961 cifs_stats_inc(&tcon->stats.cifs_stats.num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000962 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000963 cFYI(1, "Error in RMDir = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964
965 cifs_buf_release(pSMB);
966 if (rc == -EAGAIN)
967 goto RmDirRetry;
968 return rc;
969}
970
971int
Pavel Shilovskyf4367202012-03-17 11:41:12 +0300972CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
973 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974{
975 int rc = 0;
976 CREATE_DIRECTORY_REQ *pSMB = NULL;
977 CREATE_DIRECTORY_RSP *pSMBr = NULL;
978 int bytes_returned;
979 int name_len;
Pavel Shilovskyf4367202012-03-17 11:41:12 +0300980 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981
Joe Perchesb6b38f72010-04-21 03:50:45 +0000982 cFYI(1, "In CIFSSMBMkDir");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983MkDirRetry:
984 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
985 (void **) &pSMBr);
986 if (rc)
987 return rc;
988
989 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -0600990 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
Pavel Shilovskyf4367202012-03-17 11:41:12 +0300991 PATH_MAX, cifs_sb->local_nls,
992 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993 name_len++; /* trailing null */
994 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700995 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 name_len = strnlen(name, PATH_MAX);
997 name_len++; /* trailing null */
998 strncpy(pSMB->DirName, name, name_len);
999 }
1000
1001 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001002 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 pSMB->ByteCount = cpu_to_le16(name_len + 1);
1004 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1005 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001006 cifs_stats_inc(&tcon->stats.cifs_stats.num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +00001007 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001008 cFYI(1, "Error in Mkdir = %d", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07001009
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 cifs_buf_release(pSMB);
1011 if (rc == -EAGAIN)
1012 goto MkDirRetry;
1013 return rc;
1014}
1015
Steve French2dd29d32007-04-23 22:07:35 +00001016int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001017CIFSPOSIXCreate(const unsigned int xid, struct cifs_tcon *tcon,
1018 __u32 posix_flags, __u64 mode, __u16 *netfid,
1019 FILE_UNIX_BASIC_INFO *pRetData, __u32 *pOplock,
1020 const char *name, const struct nls_table *nls_codepage,
1021 int remap)
Steve French2dd29d32007-04-23 22:07:35 +00001022{
1023 TRANSACTION2_SPI_REQ *pSMB = NULL;
1024 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1025 int name_len;
1026 int rc = 0;
1027 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001028 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +00001029 OPEN_PSX_REQ *pdata;
1030 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +00001031
Joe Perchesb6b38f72010-04-21 03:50:45 +00001032 cFYI(1, "In POSIX Create");
Steve French2dd29d32007-04-23 22:07:35 +00001033PsxCreat:
1034 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1035 (void **) &pSMBr);
1036 if (rc)
1037 return rc;
1038
1039 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1040 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001041 cifsConvertToUTF16((__le16 *) pSMB->FileName, name,
1042 PATH_MAX, nls_codepage, remap);
Steve French2dd29d32007-04-23 22:07:35 +00001043 name_len++; /* trailing null */
1044 name_len *= 2;
1045 } else { /* BB improve the check for buffer overruns BB */
1046 name_len = strnlen(name, PATH_MAX);
1047 name_len++; /* trailing null */
1048 strncpy(pSMB->FileName, name, name_len);
1049 }
1050
1051 params = 6 + name_len;
1052 count = sizeof(OPEN_PSX_REQ);
1053 pSMB->MaxParameterCount = cpu_to_le16(2);
1054 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1055 pSMB->MaxSetupCount = 0;
1056 pSMB->Reserved = 0;
1057 pSMB->Flags = 0;
1058 pSMB->Timeout = 0;
1059 pSMB->Reserved2 = 0;
1060 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001061 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001062 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001063 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001064 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001065 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001066 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001067 pdata->OpenFlags = cpu_to_le32(*pOplock);
1068 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1069 pSMB->DataOffset = cpu_to_le16(offset);
1070 pSMB->SetupCount = 1;
1071 pSMB->Reserved3 = 0;
1072 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1073 byte_count = 3 /* pad */ + params + count;
1074
1075 pSMB->DataCount = cpu_to_le16(count);
1076 pSMB->ParameterCount = cpu_to_le16(params);
1077 pSMB->TotalDataCount = pSMB->DataCount;
1078 pSMB->TotalParameterCount = pSMB->ParameterCount;
1079 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1080 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001081 inc_rfc1001_len(pSMB, byte_count);
Steve French2dd29d32007-04-23 22:07:35 +00001082 pSMB->ByteCount = cpu_to_le16(byte_count);
1083 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1084 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1085 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001086 cFYI(1, "Posix create returned %d", rc);
Steve French2dd29d32007-04-23 22:07:35 +00001087 goto psx_create_err;
1088 }
1089
Joe Perchesb6b38f72010-04-21 03:50:45 +00001090 cFYI(1, "copying inode info");
Steve French2dd29d32007-04-23 22:07:35 +00001091 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1092
Jeff Layton820a8032011-05-04 08:05:26 -04001093 if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) {
Steve French2dd29d32007-04-23 22:07:35 +00001094 rc = -EIO; /* bad smb */
1095 goto psx_create_err;
1096 }
1097
1098 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001099 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001100 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001101
Steve French2dd29d32007-04-23 22:07:35 +00001102 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001103 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001104 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1105 /* Let caller know file was created so we can set the mode. */
1106 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001107 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001108 *pOplock |= CIFS_CREATE_ACTION;
1109 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001110 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1111 pRetData->Type = cpu_to_le32(-1); /* unknown */
Joe Perchesb6b38f72010-04-21 03:50:45 +00001112 cFYI(DBG2, "unknown type");
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001113 } else {
Jeff Layton820a8032011-05-04 08:05:26 -04001114 if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001115 + sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001116 cERROR(1, "Open response data too small");
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001117 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001118 goto psx_create_err;
1119 }
Steve French50c2f752007-07-13 00:33:32 +00001120 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001121 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001122 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001123 }
Steve French2dd29d32007-04-23 22:07:35 +00001124
1125psx_create_err:
1126 cifs_buf_release(pSMB);
1127
Steve French65bc98b2009-07-10 15:27:25 +00001128 if (posix_flags & SMB_O_DIRECTORY)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001129 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixmkdirs);
Steve French65bc98b2009-07-10 15:27:25 +00001130 else
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001131 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixopens);
Steve French2dd29d32007-04-23 22:07:35 +00001132
1133 if (rc == -EAGAIN)
1134 goto PsxCreat;
1135
Steve French50c2f752007-07-13 00:33:32 +00001136 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001137}
1138
Steve Frencha9d02ad2005-08-24 23:06:05 -07001139static __u16 convert_disposition(int disposition)
1140{
1141 __u16 ofun = 0;
1142
1143 switch (disposition) {
1144 case FILE_SUPERSEDE:
1145 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1146 break;
1147 case FILE_OPEN:
1148 ofun = SMBOPEN_OAPPEND;
1149 break;
1150 case FILE_CREATE:
1151 ofun = SMBOPEN_OCREATE;
1152 break;
1153 case FILE_OPEN_IF:
1154 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1155 break;
1156 case FILE_OVERWRITE:
1157 ofun = SMBOPEN_OTRUNC;
1158 break;
1159 case FILE_OVERWRITE_IF:
1160 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1161 break;
1162 default:
Joe Perchesb6b38f72010-04-21 03:50:45 +00001163 cFYI(1, "unknown disposition %d", disposition);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001164 ofun = SMBOPEN_OAPPEND; /* regular open */
1165 }
1166 return ofun;
1167}
1168
Jeff Layton35fc37d2008-05-14 10:22:03 -07001169static int
1170access_flags_to_smbopen_mode(const int access_flags)
1171{
1172 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1173
1174 if (masked_flags == GENERIC_READ)
1175 return SMBOPEN_READ;
1176 else if (masked_flags == GENERIC_WRITE)
1177 return SMBOPEN_WRITE;
1178
1179 /* just go for read/write */
1180 return SMBOPEN_READWRITE;
1181}
1182
Steve Frencha9d02ad2005-08-24 23:06:05 -07001183int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001184SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001185 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001186 const int access_flags, const int create_options, __u16 *netfid,
1187 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001188 const struct nls_table *nls_codepage, int remap)
1189{
1190 int rc = -EACCES;
1191 OPENX_REQ *pSMB = NULL;
1192 OPENX_RSP *pSMBr = NULL;
1193 int bytes_returned;
1194 int name_len;
1195 __u16 count;
1196
1197OldOpenRetry:
1198 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1199 (void **) &pSMBr);
1200 if (rc)
1201 return rc;
1202
1203 pSMB->AndXCommand = 0xFF; /* none */
1204
1205 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1206 count = 1; /* account for one byte pad to word boundary */
1207 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001208 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1209 fileName, PATH_MAX, nls_codepage, remap);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001210 name_len++; /* trailing null */
1211 name_len *= 2;
1212 } else { /* BB improve check for buffer overruns BB */
1213 count = 0; /* no pad */
1214 name_len = strnlen(fileName, PATH_MAX);
1215 name_len++; /* trailing null */
1216 strncpy(pSMB->fileName, fileName, name_len);
1217 }
1218 if (*pOplock & REQ_OPLOCK)
1219 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001220 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001221 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001222
Steve Frencha9d02ad2005-08-24 23:06:05 -07001223 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001224 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001225 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1226 /* set file as system file if special file such
1227 as fifo and server expecting SFU style and
1228 no Unix extensions */
1229
Steve French790fe572007-07-07 19:25:05 +00001230 if (create_options & CREATE_OPTION_SPECIAL)
1231 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001232 else /* BB FIXME BB */
1233 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001234
Jeff Layton67750fb2008-05-09 22:28:02 +00001235 if (create_options & CREATE_OPTION_READONLY)
1236 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001237
1238 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001239/* pSMB->CreateOptions = cpu_to_le32(create_options &
1240 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001241 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001242
1243 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001244 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001245 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001246 inc_rfc1001_len(pSMB, count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001247
1248 pSMB->ByteCount = cpu_to_le16(count);
1249 /* long_op set to 1 to allow for oplock break timeouts */
1250 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001251 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001252 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001253 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001254 cFYI(1, "Error in Open = %d", rc);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001255 } else {
1256 /* BB verify if wct == 15 */
1257
Steve French582d21e2008-05-13 04:54:12 +00001258/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001259
1260 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1261 /* Let caller know file was created so we can set the mode. */
1262 /* Do we care about the CreateAction in any other cases? */
1263 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001264/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001265 *pOplock |= CIFS_CREATE_ACTION; */
1266 /* BB FIXME END */
1267
Steve French790fe572007-07-07 19:25:05 +00001268 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001269 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1270 pfile_info->LastAccessTime = 0; /* BB fixme */
1271 pfile_info->LastWriteTime = 0; /* BB fixme */
1272 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001273 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001274 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001275 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001276 pfile_info->AllocationSize =
1277 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1278 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001279 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001280 pfile_info->DeletePending = 0;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001281 }
1282 }
1283
1284 cifs_buf_release(pSMB);
1285 if (rc == -EAGAIN)
1286 goto OldOpenRetry;
1287 return rc;
1288}
1289
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001291CIFSSMBOpen(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001293 const int access_flags, const int create_options, __u16 *netfid,
1294 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001295 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296{
1297 int rc = -EACCES;
1298 OPEN_REQ *pSMB = NULL;
1299 OPEN_RSP *pSMBr = NULL;
1300 int bytes_returned;
1301 int name_len;
1302 __u16 count;
1303
1304openRetry:
1305 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1306 (void **) &pSMBr);
1307 if (rc)
1308 return rc;
1309
1310 pSMB->AndXCommand = 0xFF; /* none */
1311
1312 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1313 count = 1; /* account for one byte pad to word boundary */
1314 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001315 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1316 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317 name_len++; /* trailing null */
1318 name_len *= 2;
1319 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001320 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321 count = 0; /* no pad */
1322 name_len = strnlen(fileName, PATH_MAX);
1323 name_len++; /* trailing null */
1324 pSMB->NameLength = cpu_to_le16(name_len);
1325 strncpy(pSMB->fileName, fileName, name_len);
1326 }
1327 if (*pOplock & REQ_OPLOCK)
1328 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001329 else if (*pOplock & REQ_BATCHOPLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1332 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -07001333 /* set file as system file if special file such
1334 as fifo and server expecting SFU style and
1335 no Unix extensions */
Steve French790fe572007-07-07 19:25:05 +00001336 if (create_options & CREATE_OPTION_SPECIAL)
Steve Frencheda3c0292005-07-21 15:20:28 -07001337 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1338 else
1339 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Jeff Layton67750fb2008-05-09 22:28:02 +00001340
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341 /* XP does not handle ATTR_POSIX_SEMANTICS */
1342 /* but it helps speed up case sensitive checks for other
1343 servers such as Samba */
1344 if (tcon->ses->capabilities & CAP_UNIX)
1345 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1346
Jeff Layton67750fb2008-05-09 22:28:02 +00001347 if (create_options & CREATE_OPTION_READONLY)
1348 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1349
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1351 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -07001352 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001353 /* BB Expirement with various impersonation levels and verify */
1354 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355 pSMB->SecurityFlags =
1356 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1357
1358 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001359 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360
1361 pSMB->ByteCount = cpu_to_le16(count);
1362 /* long_op set to 1 to allow for oplock break timeouts */
1363 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001364 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001365 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001367 cFYI(1, "Error in Open = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368 } else {
Steve French09d1db52005-04-28 22:41:08 -07001369 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1371 /* Let caller know file was created so we can set the mode. */
1372 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001373 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve French50c2f752007-07-13 00:33:32 +00001374 *pOplock |= CIFS_CREATE_ACTION;
Steve French790fe572007-07-07 19:25:05 +00001375 if (pfile_info) {
Steve French61e74802008-12-03 00:57:54 +00001376 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1377 36 /* CreationTime to Attributes */);
1378 /* the file_info buf is endian converted by caller */
1379 pfile_info->AllocationSize = pSMBr->AllocationSize;
1380 pfile_info->EndOfFile = pSMBr->EndOfFile;
1381 pfile_info->NumberOfLinks = cpu_to_le32(1);
1382 pfile_info->DeletePending = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001385
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386 cifs_buf_release(pSMB);
1387 if (rc == -EAGAIN)
1388 goto openRetry;
1389 return rc;
1390}
1391
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001392/*
1393 * Discard any remaining data in the current SMB. To do this, we borrow the
1394 * current bigbuf.
1395 */
1396static int
1397cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1398{
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001399 unsigned int rfclen = get_rfc1002_length(server->smallbuf);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001400 int remaining = rfclen + 4 - server->total_read;
1401 struct cifs_readdata *rdata = mid->callback_data;
1402
1403 while (remaining > 0) {
1404 int length;
1405
1406 length = cifs_read_from_socket(server, server->bigbuf,
1407 min_t(unsigned int, remaining,
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001408 CIFSMaxBufSize + MAX_HEADER_SIZE(server)));
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001409 if (length < 0)
1410 return length;
1411 server->total_read += length;
1412 remaining -= length;
1413 }
1414
1415 dequeue_mid(mid, rdata->result);
1416 return 0;
1417}
1418
Pavel Shilovsky09a47072012-09-18 16:20:29 -07001419int
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001420cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1421{
1422 int length, len;
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001423 unsigned int data_offset, data_len;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001424 struct cifs_readdata *rdata = mid->callback_data;
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001425 char *buf = server->smallbuf;
1426 unsigned int buflen = get_rfc1002_length(buf) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001427
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001428 cFYI(1, "%s: mid=%llu offset=%llu bytes=%u", __func__,
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001429 mid->mid, rdata->offset, rdata->bytes);
1430
1431 /*
1432 * read the rest of READ_RSP header (sans Data array), or whatever we
1433 * can if there's not enough data. At this point, we've read down to
1434 * the Mid.
1435 */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001436 len = min_t(unsigned int, buflen, server->vals->read_rsp_size) -
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001437 HEADER_SIZE(server) + 1;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001438
Jeff Layton58195752012-09-19 06:22:34 -07001439 rdata->iov.iov_base = buf + HEADER_SIZE(server) - 1;
1440 rdata->iov.iov_len = len;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001441
Jeff Layton58195752012-09-19 06:22:34 -07001442 length = cifs_readv_from_socket(server, &rdata->iov, 1, len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001443 if (length < 0)
1444 return length;
1445 server->total_read += length;
1446
1447 /* Was the SMB read successful? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001448 rdata->result = server->ops->map_error(buf, false);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001449 if (rdata->result != 0) {
1450 cFYI(1, "%s: server returned error %d", __func__,
1451 rdata->result);
1452 return cifs_readv_discard(server, mid);
1453 }
1454
1455 /* Is there enough to get to the rest of the READ_RSP header? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001456 if (server->total_read < server->vals->read_rsp_size) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001457 cFYI(1, "%s: server returned short header. got=%u expected=%zu",
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001458 __func__, server->total_read,
1459 server->vals->read_rsp_size);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001460 rdata->result = -EIO;
1461 return cifs_readv_discard(server, mid);
1462 }
1463
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001464 data_offset = server->ops->read_data_offset(buf) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001465 if (data_offset < server->total_read) {
1466 /*
1467 * win2k8 sometimes sends an offset of 0 when the read
1468 * is beyond the EOF. Treat it as if the data starts just after
1469 * the header.
1470 */
1471 cFYI(1, "%s: data offset (%u) inside read response header",
1472 __func__, data_offset);
1473 data_offset = server->total_read;
1474 } else if (data_offset > MAX_CIFS_SMALL_BUFFER_SIZE) {
1475 /* data_offset is beyond the end of smallbuf */
1476 cFYI(1, "%s: data offset (%u) beyond end of smallbuf",
1477 __func__, data_offset);
1478 rdata->result = -EIO;
1479 return cifs_readv_discard(server, mid);
1480 }
1481
1482 cFYI(1, "%s: total_read=%u data_offset=%u", __func__,
1483 server->total_read, data_offset);
1484
1485 len = data_offset - server->total_read;
1486 if (len > 0) {
1487 /* read any junk before data into the rest of smallbuf */
Jeff Layton58195752012-09-19 06:22:34 -07001488 rdata->iov.iov_base = buf + server->total_read;
1489 rdata->iov.iov_len = len;
1490 length = cifs_readv_from_socket(server, &rdata->iov, 1, len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001491 if (length < 0)
1492 return length;
1493 server->total_read += length;
1494 }
1495
1496 /* set up first iov for signature check */
Jeff Layton58195752012-09-19 06:22:34 -07001497 rdata->iov.iov_base = buf;
1498 rdata->iov.iov_len = server->total_read;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001499 cFYI(1, "0: iov_base=%p iov_len=%zu",
Jeff Layton58195752012-09-19 06:22:34 -07001500 rdata->iov.iov_base, rdata->iov.iov_len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001501
1502 /* how much data is in the response? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001503 data_len = server->ops->read_data_length(buf);
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001504 if (data_offset + data_len > buflen) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001505 /* data_len is corrupt -- discard frame */
1506 rdata->result = -EIO;
1507 return cifs_readv_discard(server, mid);
1508 }
1509
Jeff Layton8321fec2012-09-19 06:22:32 -07001510 length = rdata->read_into_pages(server, rdata, data_len);
1511 if (length < 0)
1512 return length;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001513
Jeff Layton8321fec2012-09-19 06:22:32 -07001514 server->total_read += length;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001515 rdata->bytes = length;
1516
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001517 cFYI(1, "total_read=%u buflen=%u remaining=%u", server->total_read,
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001518 buflen, data_len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001519
1520 /* discard anything left over */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001521 if (server->total_read < buflen)
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001522 return cifs_readv_discard(server, mid);
1523
1524 dequeue_mid(mid, false);
1525 return length;
1526}
1527
1528static void
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001529cifs_readv_callback(struct mid_q_entry *mid)
1530{
1531 struct cifs_readdata *rdata = mid->callback_data;
1532 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1533 struct TCP_Server_Info *server = tcon->ses->server;
Jeff Layton58195752012-09-19 06:22:34 -07001534 struct smb_rqst rqst = { .rq_iov = &rdata->iov,
1535 .rq_nvec = 1,
Jeff Layton8321fec2012-09-19 06:22:32 -07001536 .rq_pages = rdata->pages,
1537 .rq_npages = rdata->nr_pages,
1538 .rq_pagesz = rdata->pagesz,
1539 .rq_tailsz = rdata->tailsz };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001540
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001541 cFYI(1, "%s: mid=%llu state=%d result=%d bytes=%u", __func__,
1542 mid->mid, mid->mid_state, rdata->result, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001543
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001544 switch (mid->mid_state) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001545 case MID_RESPONSE_RECEIVED:
1546 /* result already set, check signature */
1547 if (server->sec_mode &
1548 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
Steve French985e4ff02012-08-03 09:42:45 -05001549 int rc = 0;
1550
Jeff Laytonbf5ea0e2012-09-18 16:20:34 -07001551 rc = cifs_verify_signature(&rqst, server,
1552 mid->sequence_number + 1);
Steve French985e4ff02012-08-03 09:42:45 -05001553 if (rc)
1554 cERROR(1, "SMB signature verification returned "
1555 "error = %d", rc);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001556 }
1557 /* FIXME: should this be counted toward the initiating task? */
1558 task_io_account_read(rdata->bytes);
1559 cifs_stats_bytes_read(tcon, rdata->bytes);
1560 break;
1561 case MID_REQUEST_SUBMITTED:
1562 case MID_RETRY_NEEDED:
1563 rdata->result = -EAGAIN;
1564 break;
1565 default:
1566 rdata->result = -EIO;
1567 }
1568
Jeff Laytonda472fc2012-03-23 14:40:53 -04001569 queue_work(cifsiod_wq, &rdata->work);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001570 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04001571 add_credits(server, 1, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001572}
1573
1574/* cifs_async_readv - send an async write, and set up mid to handle result */
1575int
1576cifs_async_readv(struct cifs_readdata *rdata)
1577{
1578 int rc;
1579 READ_REQ *smb = NULL;
1580 int wct;
1581 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
Jeff Layton58195752012-09-19 06:22:34 -07001582 struct smb_rqst rqst = { .rq_iov = &rdata->iov,
Jeff Laytonfec344e2012-09-18 16:20:35 -07001583 .rq_nvec = 1 };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001584
1585 cFYI(1, "%s: offset=%llu bytes=%u", __func__,
1586 rdata->offset, rdata->bytes);
1587
1588 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1589 wct = 12;
1590 else {
1591 wct = 10; /* old style read */
1592 if ((rdata->offset >> 32) > 0) {
1593 /* can not handle this big offset for old */
1594 return -EIO;
1595 }
1596 }
1597
1598 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **)&smb);
1599 if (rc)
1600 return rc;
1601
1602 smb->hdr.Pid = cpu_to_le16((__u16)rdata->pid);
1603 smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16));
1604
1605 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07001606 smb->Fid = rdata->cfile->fid.netfid;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001607 smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF);
1608 if (wct == 12)
1609 smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32);
1610 smb->Remaining = 0;
1611 smb->MaxCount = cpu_to_le16(rdata->bytes & 0xFFFF);
1612 smb->MaxCountHigh = cpu_to_le32(rdata->bytes >> 16);
1613 if (wct == 12)
1614 smb->ByteCount = 0;
1615 else {
1616 /* old style read */
1617 struct smb_com_readx_req *smbr =
1618 (struct smb_com_readx_req *)smb;
1619 smbr->ByteCount = 0;
1620 }
1621
1622 /* 4 for RFC1001 length + 1 for BCC */
Jeff Layton58195752012-09-19 06:22:34 -07001623 rdata->iov.iov_base = smb;
1624 rdata->iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001625
Jeff Layton6993f742012-05-16 07:13:17 -04001626 kref_get(&rdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07001627 rc = cifs_call_async(tcon->ses->server, &rqst, cifs_readv_receive,
1628 cifs_readv_callback, rdata, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001629
1630 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001631 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Jeff Layton6993f742012-05-16 07:13:17 -04001632 else
1633 kref_put(&rdata->refcount, cifs_readdata_release);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001634
1635 cifs_small_buf_release(smb);
1636 return rc;
1637}
1638
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001640CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
1641 unsigned int *nbytes, char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642{
1643 int rc = -EACCES;
1644 READ_REQ *pSMB = NULL;
1645 READ_RSP *pSMBr = NULL;
1646 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001647 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001648 int resp_buf_type = 0;
1649 struct kvec iov[1];
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001650 __u32 pid = io_parms->pid;
1651 __u16 netfid = io_parms->netfid;
1652 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001653 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001654 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655
Joe Perchesb6b38f72010-04-21 03:50:45 +00001656 cFYI(1, "Reading %d bytes on fid %d", count, netfid);
Steve French790fe572007-07-07 19:25:05 +00001657 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001658 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001659 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001660 wct = 10; /* old style read */
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001661 if ((offset >> 32) > 0) {
Steve French4c3130e2008-12-09 00:28:16 +00001662 /* can not handle this big offset for old */
1663 return -EIO;
1664 }
1665 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001666
1667 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001668 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669 if (rc)
1670 return rc;
1671
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001672 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1673 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1674
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675 /* tcon and ses pointer are checked in smb_init */
1676 if (tcon->ses->server == NULL)
1677 return -ECONNABORTED;
1678
Steve Frenchec637e32005-12-12 20:53:18 -08001679 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680 pSMB->Fid = netfid;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001681 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001682 if (wct == 12)
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001683 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001684
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685 pSMB->Remaining = 0;
1686 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1687 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001688 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001689 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1690 else {
1691 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001692 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001693 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001694 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001695 }
Steve Frenchec637e32005-12-12 20:53:18 -08001696
1697 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001698 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve Frencha761ac52007-10-18 21:45:27 +00001699 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Jeff Layton77499812011-01-11 07:24:23 -05001700 &resp_buf_type, CIFS_LOG_ERROR);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001701 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001702 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001704 cERROR(1, "Send error in read = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705 } else {
1706 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1707 data_length = data_length << 16;
1708 data_length += le16_to_cpu(pSMBr->DataLength);
1709 *nbytes = data_length;
1710
1711 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001712 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713 || (data_length > count)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001714 cFYI(1, "bad length %d for count %d",
1715 data_length, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716 rc = -EIO;
1717 *nbytes = 0;
1718 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001719 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001720 le16_to_cpu(pSMBr->DataOffset);
1721/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001722 cERROR(1, "Faulting on read rc = %d",rc);
Steve French50c2f752007-07-13 00:33:32 +00001723 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001724 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001725 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001726 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727 }
1728 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729
Steve French4b8f9302006-02-26 16:41:18 +00001730/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001731 if (*buf) {
1732 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001733 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001734 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001735 cifs_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001736 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001737 /* return buffer to caller to free */
1738 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001739 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001740 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001741 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001742 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001743 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001744
1745 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746 since file handle passed in no longer valid */
1747 return rc;
1748}
1749
Steve Frenchec637e32005-12-12 20:53:18 -08001750
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001752CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001753 unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001754 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755{
1756 int rc = -EACCES;
1757 WRITE_REQ *pSMB = NULL;
1758 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001759 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001760 __u32 bytes_sent;
1761 __u16 byte_count;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001762 __u32 pid = io_parms->pid;
1763 __u16 netfid = io_parms->netfid;
1764 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001765 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001766 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767
Steve Frencha24e2d72010-04-03 17:20:21 +00001768 *nbytes = 0;
1769
Joe Perchesb6b38f72010-04-21 03:50:45 +00001770 /* cFYI(1, "write at %lld %d bytes", offset, count);*/
Steve French790fe572007-07-07 19:25:05 +00001771 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001772 return -ECONNABORTED;
1773
Steve French790fe572007-07-07 19:25:05 +00001774 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001775 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001776 else {
Steve French1c955182005-08-30 20:58:07 -07001777 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001778 if ((offset >> 32) > 0) {
1779 /* can not handle big offset for old srv */
1780 return -EIO;
1781 }
1782 }
Steve French1c955182005-08-30 20:58:07 -07001783
1784 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785 (void **) &pSMBr);
1786 if (rc)
1787 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001788
1789 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1790 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1791
Linus Torvalds1da177e2005-04-16 15:20:36 -07001792 /* tcon and ses pointer are checked in smb_init */
1793 if (tcon->ses->server == NULL)
1794 return -ECONNABORTED;
1795
1796 pSMB->AndXCommand = 0xFF; /* none */
1797 pSMB->Fid = netfid;
1798 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001799 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001800 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001801
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802 pSMB->Reserved = 0xFFFFFFFF;
1803 pSMB->WriteMode = 0;
1804 pSMB->Remaining = 0;
1805
Steve French50c2f752007-07-13 00:33:32 +00001806 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807 can send more if LARGE_WRITE_X capability returned by the server and if
1808 our buffer is big enough or if we convert to iovecs on socket writes
1809 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001810 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1812 } else {
1813 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1814 & ~0xFF;
1815 }
1816
1817 if (bytes_sent > count)
1818 bytes_sent = count;
1819 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001820 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001821 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001822 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001823 else if (ubuf) {
1824 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001825 cifs_buf_release(pSMB);
1826 return -EFAULT;
1827 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001828 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001829 /* No buffer */
1830 cifs_buf_release(pSMB);
1831 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001832 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001833 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001834 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001835 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001836 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001837
Linus Torvalds1da177e2005-04-16 15:20:36 -07001838 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1839 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001840 inc_rfc1001_len(pSMB, byte_count);
Steve French1c955182005-08-30 20:58:07 -07001841
Steve French790fe572007-07-07 19:25:05 +00001842 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001843 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001844 else { /* old style write has byte count 4 bytes earlier
1845 so 4 bytes pad */
1846 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001847 (struct smb_com_writex_req *)pSMB;
1848 pSMBW->ByteCount = cpu_to_le16(byte_count);
1849 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850
1851 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1852 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001853 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00001855 cFYI(1, "Send error in write = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856 } else {
1857 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1858 *nbytes = (*nbytes) << 16;
1859 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301860
1861 /*
1862 * Mask off high 16 bits when bytes written as returned by the
1863 * server is greater than bytes requested by the client. Some
1864 * OS/2 servers are known to set incorrect CountHigh values.
1865 */
1866 if (*nbytes > count)
1867 *nbytes &= 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868 }
1869
1870 cifs_buf_release(pSMB);
1871
Steve French50c2f752007-07-13 00:33:32 +00001872 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873 since file handle passed in no longer valid */
1874
1875 return rc;
1876}
1877
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001878void
1879cifs_writedata_release(struct kref *refcount)
1880{
1881 struct cifs_writedata *wdata = container_of(refcount,
1882 struct cifs_writedata, refcount);
1883
1884 if (wdata->cfile)
1885 cifsFileInfo_put(wdata->cfile);
1886
1887 kfree(wdata);
1888}
1889
1890/*
1891 * Write failed with a retryable error. Resend the write request. It's also
1892 * possible that the page was redirtied so re-clean the page.
1893 */
1894static void
1895cifs_writev_requeue(struct cifs_writedata *wdata)
1896{
1897 int i, rc;
1898 struct inode *inode = wdata->cfile->dentry->d_inode;
Pavel Shilovskyc9de5c82012-09-18 16:20:29 -07001899 struct TCP_Server_Info *server;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001900
1901 for (i = 0; i < wdata->nr_pages; i++) {
1902 lock_page(wdata->pages[i]);
1903 clear_page_dirty_for_io(wdata->pages[i]);
1904 }
1905
1906 do {
Pavel Shilovskyc9de5c82012-09-18 16:20:29 -07001907 server = tlink_tcon(wdata->cfile->tlink)->ses->server;
1908 rc = server->ops->async_writev(wdata);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001909 } while (rc == -EAGAIN);
1910
1911 for (i = 0; i < wdata->nr_pages; i++) {
1912 if (rc != 0)
1913 SetPageError(wdata->pages[i]);
1914 unlock_page(wdata->pages[i]);
1915 }
1916
1917 mapping_set_error(inode->i_mapping, rc);
1918 kref_put(&wdata->refcount, cifs_writedata_release);
1919}
1920
Jeff Laytonc2e87642012-03-23 14:40:55 -04001921void
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001922cifs_writev_complete(struct work_struct *work)
1923{
1924 struct cifs_writedata *wdata = container_of(work,
1925 struct cifs_writedata, work);
1926 struct inode *inode = wdata->cfile->dentry->d_inode;
1927 int i = 0;
1928
1929 if (wdata->result == 0) {
Jeff Layton597b0272012-03-23 14:40:56 -04001930 spin_lock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001931 cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
Jeff Layton597b0272012-03-23 14:40:56 -04001932 spin_unlock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001933 cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
1934 wdata->bytes);
1935 } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
1936 return cifs_writev_requeue(wdata);
1937
1938 for (i = 0; i < wdata->nr_pages; i++) {
1939 struct page *page = wdata->pages[i];
1940 if (wdata->result == -EAGAIN)
1941 __set_page_dirty_nobuffers(page);
1942 else if (wdata->result < 0)
1943 SetPageError(page);
1944 end_page_writeback(page);
1945 page_cache_release(page);
1946 }
1947 if (wdata->result != -EAGAIN)
1948 mapping_set_error(inode->i_mapping, wdata->result);
1949 kref_put(&wdata->refcount, cifs_writedata_release);
1950}
1951
1952struct cifs_writedata *
Jeff Laytonc2e87642012-03-23 14:40:55 -04001953cifs_writedata_alloc(unsigned int nr_pages, work_func_t complete)
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001954{
1955 struct cifs_writedata *wdata;
1956
1957 /* this would overflow */
1958 if (nr_pages == 0) {
1959 cERROR(1, "%s: called with nr_pages == 0!", __func__);
1960 return NULL;
1961 }
1962
1963 /* writedata + number of page pointers */
1964 wdata = kzalloc(sizeof(*wdata) +
1965 sizeof(struct page *) * (nr_pages - 1), GFP_NOFS);
1966 if (wdata != NULL) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001967 kref_init(&wdata->refcount);
Jeff Laytonda82f7e2012-03-23 14:40:56 -04001968 INIT_LIST_HEAD(&wdata->list);
1969 init_completion(&wdata->done);
1970 INIT_WORK(&wdata->work, complete);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001971 }
1972 return wdata;
1973}
1974
1975/*
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001976 * Check the mid_state and signature on received buffer (if any), and queue the
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001977 * workqueue completion task.
1978 */
1979static void
1980cifs_writev_callback(struct mid_q_entry *mid)
1981{
1982 struct cifs_writedata *wdata = mid->callback_data;
Steve French96daf2b2011-05-27 04:34:02 +00001983 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001984 unsigned int written;
1985 WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
1986
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001987 switch (mid->mid_state) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001988 case MID_RESPONSE_RECEIVED:
1989 wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
1990 if (wdata->result != 0)
1991 break;
1992
1993 written = le16_to_cpu(smb->CountHigh);
1994 written <<= 16;
1995 written += le16_to_cpu(smb->Count);
1996 /*
1997 * Mask off high 16 bits when bytes written as returned
1998 * by the server is greater than bytes requested by the
1999 * client. OS/2 servers are known to set incorrect
2000 * CountHigh values.
2001 */
2002 if (written > wdata->bytes)
2003 written &= 0xFFFF;
2004
2005 if (written < wdata->bytes)
2006 wdata->result = -ENOSPC;
2007 else
2008 wdata->bytes = written;
2009 break;
2010 case MID_REQUEST_SUBMITTED:
2011 case MID_RETRY_NEEDED:
2012 wdata->result = -EAGAIN;
2013 break;
2014 default:
2015 wdata->result = -EIO;
2016 break;
2017 }
2018
Jeff Laytonda472fc2012-03-23 14:40:53 -04002019 queue_work(cifsiod_wq, &wdata->work);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002020 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002021 add_credits(tcon->ses->server, 1, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002022}
2023
2024/* cifs_async_writev - send an async write, and set up mid to handle result */
2025int
2026cifs_async_writev(struct cifs_writedata *wdata)
2027{
Jeff Laytoneddb0792012-09-18 16:20:35 -07002028 int rc = -EACCES;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002029 WRITE_REQ *smb = NULL;
2030 int wct;
Steve French96daf2b2011-05-27 04:34:02 +00002031 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytoneddb0792012-09-18 16:20:35 -07002032 struct kvec iov;
Jeff Laytonfec344e2012-09-18 16:20:35 -07002033 struct smb_rqst rqst = { };
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002034
2035 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
2036 wct = 14;
2037 } else {
2038 wct = 12;
2039 if (wdata->offset >> 32 > 0) {
2040 /* can not handle big offset for old srv */
2041 return -EIO;
2042 }
2043 }
2044
2045 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
2046 if (rc)
2047 goto async_writev_out;
2048
Jeff Laytonfe5f5d22012-03-23 14:40:55 -04002049 smb->hdr.Pid = cpu_to_le16((__u16)wdata->pid);
2050 smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16));
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002051
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002052 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07002053 smb->Fid = wdata->cfile->fid.netfid;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002054 smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
2055 if (wct == 14)
2056 smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
2057 smb->Reserved = 0xFFFFFFFF;
2058 smb->WriteMode = 0;
2059 smb->Remaining = 0;
2060
2061 smb->DataOffset =
2062 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
2063
2064 /* 4 for RFC1001 length + 1 for BCC */
Jeff Laytoneddb0792012-09-18 16:20:35 -07002065 iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4 + 1;
2066 iov.iov_base = smb;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002067
Jeff Laytoneddb0792012-09-18 16:20:35 -07002068 rqst.rq_iov = &iov;
2069 rqst.rq_nvec = 1;
2070 rqst.rq_pages = wdata->pages;
2071 rqst.rq_npages = wdata->nr_pages;
2072 rqst.rq_pagesz = wdata->pagesz;
2073 rqst.rq_tailsz = wdata->tailsz;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002074
2075 cFYI(1, "async write at %llu %u bytes", wdata->offset, wdata->bytes);
2076
2077 smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
2078 smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16);
2079
2080 if (wct == 14) {
2081 inc_rfc1001_len(&smb->hdr, wdata->bytes + 1);
2082 put_bcc(wdata->bytes + 1, &smb->hdr);
2083 } else {
2084 /* wct == 12 */
2085 struct smb_com_writex_req *smbw =
2086 (struct smb_com_writex_req *)smb;
2087 inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
2088 put_bcc(wdata->bytes + 5, &smbw->hdr);
Jeff Laytoneddb0792012-09-18 16:20:35 -07002089 iov.iov_len += 4; /* pad bigger by four bytes */
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002090 }
2091
2092 kref_get(&wdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07002093 rc = cifs_call_async(tcon->ses->server, &rqst, NULL,
2094 cifs_writev_callback, wdata, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002095
2096 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002097 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002098 else
2099 kref_put(&wdata->refcount, cifs_writedata_release);
2100
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002101async_writev_out:
2102 cifs_small_buf_release(smb);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002103 return rc;
2104}
2105
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002106int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002107CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
Pavel Shilovskyba9ad7252012-09-18 16:20:30 -07002108 unsigned int *nbytes, struct kvec *iov, int n_vec)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002109{
2110 int rc = -EACCES;
2111 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08002112 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002113 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08002114 int resp_buf_type = 0;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002115 __u32 pid = io_parms->pid;
2116 __u16 netfid = io_parms->netfid;
2117 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00002118 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002119 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002120
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04002121 *nbytes = 0;
2122
Joe Perchesb6b38f72010-04-21 03:50:45 +00002123 cFYI(1, "write2 at %lld %d bytes", (long long)offset, count);
Steve Frenchff7feac2005-11-15 16:45:16 -08002124
Steve French4c3130e2008-12-09 00:28:16 +00002125 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07002126 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00002127 } else {
Steve French8cc64c62005-10-03 13:49:43 -07002128 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00002129 if ((offset >> 32) > 0) {
2130 /* can not handle big offset for old srv */
2131 return -EIO;
2132 }
2133 }
Steve French8cc64c62005-10-03 13:49:43 -07002134 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002135 if (rc)
2136 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002137
2138 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
2139 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
2140
Linus Torvalds1da177e2005-04-16 15:20:36 -07002141 /* tcon and ses pointer are checked in smb_init */
2142 if (tcon->ses->server == NULL)
2143 return -ECONNABORTED;
2144
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002145 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002146 pSMB->Fid = netfid;
2147 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00002148 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002149 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002150 pSMB->Reserved = 0xFFFFFFFF;
2151 pSMB->WriteMode = 0;
2152 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002153
Linus Torvalds1da177e2005-04-16 15:20:36 -07002154 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00002155 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002156
Steve French3e844692005-10-03 13:37:24 -07002157 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
2158 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002159 /* header + 1 byte pad */
2160 smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
Steve French790fe572007-07-07 19:25:05 +00002161 if (wct == 14)
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002162 inc_rfc1001_len(pSMB, count + 1);
Steve French8cc64c62005-10-03 13:49:43 -07002163 else /* wct == 12 */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002164 inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
Steve French790fe572007-07-07 19:25:05 +00002165 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002166 pSMB->ByteCount = cpu_to_le16(count + 1);
2167 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00002168 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07002169 (struct smb_com_writex_req *)pSMB;
2170 pSMBW->ByteCount = cpu_to_le16(count + 5);
2171 }
Steve French3e844692005-10-03 13:37:24 -07002172 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00002173 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08002174 iov[0].iov_len = smb_hdr_len + 4;
2175 else /* wct == 12 pad bigger by four bytes */
2176 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00002177
Steve French3e844692005-10-03 13:37:24 -07002178
Pavel Shilovskyba9ad7252012-09-18 16:20:30 -07002179 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002180 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002181 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002182 cFYI(1, "Send error Write2 = %d", rc);
Steve French790fe572007-07-07 19:25:05 +00002183 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08002184 /* presumably this can not happen, but best to be safe */
2185 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002186 } else {
Steve Frenchad7a2922008-02-07 23:25:02 +00002187 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002188 *nbytes = le16_to_cpu(pSMBr->CountHigh);
2189 *nbytes = (*nbytes) << 16;
2190 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05302191
2192 /*
2193 * Mask off high 16 bits when bytes written as returned by the
2194 * server is greater than bytes requested by the client. OS/2
2195 * servers are known to set incorrect CountHigh values.
2196 */
2197 if (*nbytes > count)
2198 *nbytes &= 0xFFFF;
Steve French50c2f752007-07-13 00:33:32 +00002199 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200
Steve French4b8f9302006-02-26 16:41:18 +00002201/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00002202 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002203 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00002204 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002205 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002206
Steve French50c2f752007-07-13 00:33:32 +00002207 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002208 since file handle passed in no longer valid */
2209
2210 return rc;
2211}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002212
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002213int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon,
2214 const __u16 netfid, const __u8 lock_type, const __u32 num_unlock,
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002215 const __u32 num_lock, LOCKING_ANDX_RANGE *buf)
2216{
2217 int rc = 0;
2218 LOCK_REQ *pSMB = NULL;
2219 struct kvec iov[2];
2220 int resp_buf_type;
2221 __u16 count;
2222
2223 cFYI(1, "cifs_lockv num lock %d num unlock %d", num_lock, num_unlock);
2224
2225 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2226 if (rc)
2227 return rc;
2228
2229 pSMB->Timeout = 0;
2230 pSMB->NumberOfLocks = cpu_to_le16(num_lock);
2231 pSMB->NumberOfUnlocks = cpu_to_le16(num_unlock);
2232 pSMB->LockType = lock_type;
2233 pSMB->AndXCommand = 0xFF; /* none */
2234 pSMB->Fid = netfid; /* netfid stays le */
2235
2236 count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2237 inc_rfc1001_len(pSMB, count);
2238 pSMB->ByteCount = cpu_to_le16(count);
2239
2240 iov[0].iov_base = (char *)pSMB;
2241 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 -
2242 (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2243 iov[1].iov_base = (char *)buf;
2244 iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2245
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002246 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002247 rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP);
2248 if (rc)
2249 cFYI(1, "Send error in cifs_lockv = %d", rc);
2250
2251 return rc;
2252}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002253
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002255CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002256 const __u16 smb_file_id, const __u32 netpid, const __u64 len,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002257 const __u64 offset, const __u32 numUnlock,
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002258 const __u32 numLock, const __u8 lockType,
2259 const bool waitFlag, const __u8 oplock_level)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002260{
2261 int rc = 0;
2262 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002263/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002264 int bytes_returned;
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002265 int flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002266 __u16 count;
2267
Joe Perchesb6b38f72010-04-21 03:50:45 +00002268 cFYI(1, "CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock);
Steve French46810cb2005-04-28 22:41:09 -07002269 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2270
Linus Torvalds1da177e2005-04-16 15:20:36 -07002271 if (rc)
2272 return rc;
2273
Steve French790fe572007-07-07 19:25:05 +00002274 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002275 /* no response expected */
2276 flags = CIFS_ASYNC_OP | CIFS_OBREAK_OP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002277 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00002278 } else if (waitFlag) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002279 flags = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002280 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
2281 } else {
2282 pSMB->Timeout = 0;
2283 }
2284
2285 pSMB->NumberOfLocks = cpu_to_le16(numLock);
2286 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
2287 pSMB->LockType = lockType;
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002288 pSMB->OplockLevel = oplock_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002289 pSMB->AndXCommand = 0xFF; /* none */
2290 pSMB->Fid = smb_file_id; /* netfid stays le */
2291
Steve French790fe572007-07-07 19:25:05 +00002292 if ((numLock != 0) || (numUnlock != 0)) {
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002293 pSMB->Locks[0].Pid = cpu_to_le16(netpid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002294 /* BB where to store pid high? */
2295 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
2296 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
2297 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
2298 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
2299 count = sizeof(LOCKING_ANDX_RANGE);
2300 } else {
2301 /* oplock break */
2302 count = 0;
2303 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002304 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002305 pSMB->ByteCount = cpu_to_le16(count);
2306
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002307 if (waitFlag) {
2308 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002309 (struct smb_hdr *) pSMB, &bytes_returned);
Steve French133672e2007-11-13 22:41:37 +00002310 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002311 } else {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002312 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, flags);
Steve French133672e2007-11-13 22:41:37 +00002313 /* SMB buffer freed by function above */
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002314 }
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002315 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002316 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002317 cFYI(1, "Send error in Lock = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002318
Steve French50c2f752007-07-13 00:33:32 +00002319 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002320 since file handle passed in no longer valid */
2321 return rc;
2322}
2323
2324int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002325CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002326 const __u16 smb_file_id, const __u32 netpid,
2327 const loff_t start_offset, const __u64 len,
2328 struct file_lock *pLockData, const __u16 lock_type,
2329 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00002330{
2331 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2332 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00002333 struct cifs_posix_lock *parm_data;
2334 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00002335 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00002336 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00002337 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00002338 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00002339 struct kvec iov[1];
Steve French08547b02006-02-28 22:39:25 +00002340
Joe Perchesb6b38f72010-04-21 03:50:45 +00002341 cFYI(1, "Posix Lock");
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002342
Steve French08547b02006-02-28 22:39:25 +00002343 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
2344
2345 if (rc)
2346 return rc;
2347
2348 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
2349
Steve French50c2f752007-07-13 00:33:32 +00002350 params = 6;
Steve French08547b02006-02-28 22:39:25 +00002351 pSMB->MaxSetupCount = 0;
2352 pSMB->Reserved = 0;
2353 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00002354 pSMB->Reserved2 = 0;
2355 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2356 offset = param_offset + params;
2357
Steve French08547b02006-02-28 22:39:25 +00002358 count = sizeof(struct cifs_posix_lock);
2359 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002360 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00002361 pSMB->SetupCount = 1;
2362 pSMB->Reserved3 = 0;
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002363 if (pLockData)
Steve French08547b02006-02-28 22:39:25 +00002364 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2365 else
2366 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2367 byte_count = 3 /* pad */ + params + count;
2368 pSMB->DataCount = cpu_to_le16(count);
2369 pSMB->ParameterCount = cpu_to_le16(params);
2370 pSMB->TotalDataCount = pSMB->DataCount;
2371 pSMB->TotalParameterCount = pSMB->ParameterCount;
2372 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00002373 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00002374 (((char *) &pSMB->hdr.Protocol) + offset);
2375
2376 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00002377 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00002378 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00002379 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00002380 pSMB->Timeout = cpu_to_le32(-1);
2381 } else
2382 pSMB->Timeout = 0;
2383
Pavel Shilovsky4f6bcec2011-10-22 15:33:30 +04002384 parm_data->pid = cpu_to_le32(netpid);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002385 parm_data->start = cpu_to_le64(start_offset);
Steve Frenchcec6815a2006-05-30 18:07:17 +00002386 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00002387
2388 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00002389 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00002390 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
2391 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002392 inc_rfc1001_len(pSMB, byte_count);
Steve French08547b02006-02-28 22:39:25 +00002393 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002394 if (waitFlag) {
2395 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2396 (struct smb_hdr *) pSMBr, &bytes_returned);
2397 } else {
Steve French133672e2007-11-13 22:41:37 +00002398 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002399 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French133672e2007-11-13 22:41:37 +00002400 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
2401 &resp_buf_type, timeout);
2402 pSMB = NULL; /* request buf already freed by SendReceive2. Do
2403 not try to free it twice below on exit */
2404 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002405 }
2406
Steve French08547b02006-02-28 22:39:25 +00002407 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002408 cFYI(1, "Send error in Posix Lock = %d", rc);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002409 } else if (pLockData) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002410 /* lock structure can be returned on get */
2411 __u16 data_offset;
2412 __u16 data_count;
2413 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00002414
Jeff Layton820a8032011-05-04 08:05:26 -04002415 if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002416 rc = -EIO; /* bad smb */
2417 goto plk_err_exit;
2418 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002419 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2420 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00002421 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002422 rc = -EIO;
2423 goto plk_err_exit;
2424 }
2425 parm_data = (struct cifs_posix_lock *)
2426 ((char *)&pSMBr->hdr.Protocol + data_offset);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002427 if (parm_data->lock_type == __constant_cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002428 pLockData->fl_type = F_UNLCK;
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002429 else {
2430 if (parm_data->lock_type ==
2431 __constant_cpu_to_le16(CIFS_RDLCK))
2432 pLockData->fl_type = F_RDLCK;
2433 else if (parm_data->lock_type ==
2434 __constant_cpu_to_le16(CIFS_WRLCK))
2435 pLockData->fl_type = F_WRLCK;
2436
Steve French5443d132011-03-13 05:08:25 +00002437 pLockData->fl_start = le64_to_cpu(parm_data->start);
2438 pLockData->fl_end = pLockData->fl_start +
2439 le64_to_cpu(parm_data->length) - 1;
2440 pLockData->fl_pid = le32_to_cpu(parm_data->pid);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002441 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002442 }
Steve French50c2f752007-07-13 00:33:32 +00002443
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002444plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00002445 if (pSMB)
2446 cifs_small_buf_release(pSMB);
2447
Steve French133672e2007-11-13 22:41:37 +00002448 if (resp_buf_type == CIFS_SMALL_BUFFER)
2449 cifs_small_buf_release(iov[0].iov_base);
2450 else if (resp_buf_type == CIFS_LARGE_BUFFER)
2451 cifs_buf_release(iov[0].iov_base);
2452
Steve French08547b02006-02-28 22:39:25 +00002453 /* Note: On -EAGAIN error only caller can retry on handle based calls
2454 since file handle passed in no longer valid */
2455
2456 return rc;
2457}
2458
2459
2460int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002461CIFSSMBClose(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002462{
2463 int rc = 0;
2464 CLOSE_REQ *pSMB = NULL;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002465 cFYI(1, "In CIFSSMBClose");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002466
2467/* do not retry on dead session on close */
2468 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00002469 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002470 return 0;
2471 if (rc)
2472 return rc;
2473
Linus Torvalds1da177e2005-04-16 15:20:36 -07002474 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00002475 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002476 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002477 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002478 cifs_stats_inc(&tcon->stats.cifs_stats.num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002479 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00002480 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002481 /* EINTR is expected when user ctl-c to kill app */
Joe Perchesb6b38f72010-04-21 03:50:45 +00002482 cERROR(1, "Send error in Close = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002483 }
2484 }
2485
Linus Torvalds1da177e2005-04-16 15:20:36 -07002486 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00002487 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002488 rc = 0;
2489
2490 return rc;
2491}
2492
2493int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002494CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Steve Frenchb298f222009-02-21 21:17:43 +00002495{
2496 int rc = 0;
2497 FLUSH_REQ *pSMB = NULL;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002498 cFYI(1, "In CIFSSMBFlush");
Steve Frenchb298f222009-02-21 21:17:43 +00002499
2500 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
2501 if (rc)
2502 return rc;
2503
2504 pSMB->FileID = (__u16) smb_file_id;
2505 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002506 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002507 cifs_stats_inc(&tcon->stats.cifs_stats.num_flushes);
Steve Frenchb298f222009-02-21 21:17:43 +00002508 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002509 cERROR(1, "Send error in Flush = %d", rc);
Steve Frenchb298f222009-02-21 21:17:43 +00002510
2511 return rc;
2512}
2513
2514int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002515CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002516 const char *from_name, const char *to_name,
2517 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002518{
2519 int rc = 0;
2520 RENAME_REQ *pSMB = NULL;
2521 RENAME_RSP *pSMBr = NULL;
2522 int bytes_returned;
2523 int name_len, name_len2;
2524 __u16 count;
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002525 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002526
Joe Perchesb6b38f72010-04-21 03:50:45 +00002527 cFYI(1, "In CIFSSMBRename");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002528renameRetry:
2529 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
2530 (void **) &pSMBr);
2531 if (rc)
2532 return rc;
2533
2534 pSMB->BufferFormat = 0x04;
2535 pSMB->SearchAttributes =
2536 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2537 ATTR_DIRECTORY);
2538
2539 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002540 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2541 from_name, PATH_MAX,
2542 cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002543 name_len++; /* trailing null */
2544 name_len *= 2;
2545 pSMB->OldFileName[name_len] = 0x04; /* pad */
2546 /* protocol requires ASCII signature byte on Unicode string */
2547 pSMB->OldFileName[name_len + 1] = 0x00;
2548 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002549 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002550 to_name, PATH_MAX, cifs_sb->local_nls,
2551 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002552 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2553 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002554 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002555 name_len = strnlen(from_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002556 name_len++; /* trailing null */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002557 strncpy(pSMB->OldFileName, from_name, name_len);
2558 name_len2 = strnlen(to_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002559 name_len2++; /* trailing null */
2560 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002561 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002562 name_len2++; /* trailing null */
2563 name_len2++; /* signature byte */
2564 }
2565
2566 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002567 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002568 pSMB->ByteCount = cpu_to_le16(count);
2569
2570 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2571 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002572 cifs_stats_inc(&tcon->stats.cifs_stats.num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002573 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002574 cFYI(1, "Send error in rename = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002575
Linus Torvalds1da177e2005-04-16 15:20:36 -07002576 cifs_buf_release(pSMB);
2577
2578 if (rc == -EAGAIN)
2579 goto renameRetry;
2580
2581 return rc;
2582}
2583
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002584int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002585 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002586 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002587{
2588 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2589 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002590 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002591 char *data_offset;
2592 char dummy_string[30];
2593 int rc = 0;
2594 int bytes_returned = 0;
2595 int len_of_str;
2596 __u16 params, param_offset, offset, count, byte_count;
2597
Joe Perchesb6b38f72010-04-21 03:50:45 +00002598 cFYI(1, "Rename to File by handle");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002599 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2600 (void **) &pSMBr);
2601 if (rc)
2602 return rc;
2603
2604 params = 6;
2605 pSMB->MaxSetupCount = 0;
2606 pSMB->Reserved = 0;
2607 pSMB->Flags = 0;
2608 pSMB->Timeout = 0;
2609 pSMB->Reserved2 = 0;
2610 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2611 offset = param_offset + params;
2612
2613 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2614 rename_info = (struct set_file_rename *) data_offset;
2615 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002616 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002617 pSMB->SetupCount = 1;
2618 pSMB->Reserved3 = 0;
2619 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2620 byte_count = 3 /* pad */ + params;
2621 pSMB->ParameterCount = cpu_to_le16(params);
2622 pSMB->TotalParameterCount = pSMB->ParameterCount;
2623 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2624 pSMB->DataOffset = cpu_to_le16(offset);
2625 /* construct random name ".cifs_tmp<inodenum><mid>" */
2626 rename_info->overwrite = cpu_to_le32(1);
2627 rename_info->root_fid = 0;
2628 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002629 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002630 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
Steve Frenchacbbb762012-01-18 22:32:33 -06002631 len_of_str =
2632 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002633 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002634 } else {
Steve Frenchacbbb762012-01-18 22:32:33 -06002635 len_of_str =
2636 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002637 target_name, PATH_MAX, nls_codepage,
2638 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002639 }
2640 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002641 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002642 byte_count += count;
2643 pSMB->DataCount = cpu_to_le16(count);
2644 pSMB->TotalDataCount = pSMB->DataCount;
2645 pSMB->Fid = netfid;
2646 pSMB->InformationLevel =
2647 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2648 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002649 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002650 pSMB->ByteCount = cpu_to_le16(byte_count);
2651 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002652 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002653 cifs_stats_inc(&pTcon->stats.cifs_stats.num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002654 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002655 cFYI(1, "Send error in Rename (by file handle) = %d", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07002656
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657 cifs_buf_release(pSMB);
2658
2659 /* Note: On -EAGAIN error only caller can retry on handle based calls
2660 since file handle passed in no longer valid */
2661
2662 return rc;
2663}
2664
2665int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002666CIFSSMBCopy(const unsigned int xid, struct cifs_tcon *tcon,
2667 const char *fromName, const __u16 target_tid, const char *toName,
2668 const int flags, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002669{
2670 int rc = 0;
2671 COPY_REQ *pSMB = NULL;
2672 COPY_RSP *pSMBr = NULL;
2673 int bytes_returned;
2674 int name_len, name_len2;
2675 __u16 count;
2676
Joe Perchesb6b38f72010-04-21 03:50:45 +00002677 cFYI(1, "In CIFSSMBCopy");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002678copyRetry:
2679 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2680 (void **) &pSMBr);
2681 if (rc)
2682 return rc;
2683
2684 pSMB->BufferFormat = 0x04;
2685 pSMB->Tid2 = target_tid;
2686
2687 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2688
2689 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002690 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2691 fromName, PATH_MAX, nls_codepage,
2692 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002693 name_len++; /* trailing null */
2694 name_len *= 2;
2695 pSMB->OldFileName[name_len] = 0x04; /* pad */
2696 /* protocol requires ASCII signature byte on Unicode string */
2697 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002698 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002699 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2700 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002701 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2702 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002703 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704 name_len = strnlen(fromName, PATH_MAX);
2705 name_len++; /* trailing null */
2706 strncpy(pSMB->OldFileName, fromName, name_len);
2707 name_len2 = strnlen(toName, PATH_MAX);
2708 name_len2++; /* trailing null */
2709 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2710 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2711 name_len2++; /* trailing null */
2712 name_len2++; /* signature byte */
2713 }
2714
2715 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002716 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002717 pSMB->ByteCount = cpu_to_le16(count);
2718
2719 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2720 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2721 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002722 cFYI(1, "Send error in copy = %d with %d files copied",
2723 rc, le16_to_cpu(pSMBr->CopyCount));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002724 }
Steve French0d817bc2008-05-22 02:02:03 +00002725 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002726
2727 if (rc == -EAGAIN)
2728 goto copyRetry;
2729
2730 return rc;
2731}
2732
2733int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002734CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735 const char *fromName, const char *toName,
2736 const struct nls_table *nls_codepage)
2737{
2738 TRANSACTION2_SPI_REQ *pSMB = NULL;
2739 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2740 char *data_offset;
2741 int name_len;
2742 int name_len_target;
2743 int rc = 0;
2744 int bytes_returned = 0;
2745 __u16 params, param_offset, offset, byte_count;
2746
Joe Perchesb6b38f72010-04-21 03:50:45 +00002747 cFYI(1, "In Symlink Unix style");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748createSymLinkRetry:
2749 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2750 (void **) &pSMBr);
2751 if (rc)
2752 return rc;
2753
2754 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2755 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06002756 cifs_strtoUTF16((__le16 *) pSMB->FileName, fromName,
2757 /* find define for this maxpathcomponent */
2758 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002759 name_len++; /* trailing null */
2760 name_len *= 2;
2761
Steve French50c2f752007-07-13 00:33:32 +00002762 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002763 name_len = strnlen(fromName, PATH_MAX);
2764 name_len++; /* trailing null */
2765 strncpy(pSMB->FileName, fromName, name_len);
2766 }
2767 params = 6 + name_len;
2768 pSMB->MaxSetupCount = 0;
2769 pSMB->Reserved = 0;
2770 pSMB->Flags = 0;
2771 pSMB->Timeout = 0;
2772 pSMB->Reserved2 = 0;
2773 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002774 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002775 offset = param_offset + params;
2776
2777 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2778 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2779 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06002780 cifs_strtoUTF16((__le16 *) data_offset, toName, PATH_MAX
2781 /* find define for this maxpathcomponent */
2782 , nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002783 name_len_target++; /* trailing null */
2784 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002785 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002786 name_len_target = strnlen(toName, PATH_MAX);
2787 name_len_target++; /* trailing null */
2788 strncpy(data_offset, toName, name_len_target);
2789 }
2790
2791 pSMB->MaxParameterCount = cpu_to_le16(2);
2792 /* BB find exact max on data count below from sess */
2793 pSMB->MaxDataCount = cpu_to_le16(1000);
2794 pSMB->SetupCount = 1;
2795 pSMB->Reserved3 = 0;
2796 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2797 byte_count = 3 /* pad */ + params + name_len_target;
2798 pSMB->DataCount = cpu_to_le16(name_len_target);
2799 pSMB->ParameterCount = cpu_to_le16(params);
2800 pSMB->TotalDataCount = pSMB->DataCount;
2801 pSMB->TotalParameterCount = pSMB->ParameterCount;
2802 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2803 pSMB->DataOffset = cpu_to_le16(offset);
2804 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2805 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002806 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002807 pSMB->ByteCount = cpu_to_le16(byte_count);
2808 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2809 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002810 cifs_stats_inc(&tcon->stats.cifs_stats.num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002811 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002812 cFYI(1, "Send error in SetPathInfo create symlink = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002813
Steve French0d817bc2008-05-22 02:02:03 +00002814 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002815
2816 if (rc == -EAGAIN)
2817 goto createSymLinkRetry;
2818
2819 return rc;
2820}
2821
2822int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002823CIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002824 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002825 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002826{
2827 TRANSACTION2_SPI_REQ *pSMB = NULL;
2828 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2829 char *data_offset;
2830 int name_len;
2831 int name_len_target;
2832 int rc = 0;
2833 int bytes_returned = 0;
2834 __u16 params, param_offset, offset, byte_count;
2835
Joe Perchesb6b38f72010-04-21 03:50:45 +00002836 cFYI(1, "In Create Hard link Unix style");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002837createHardLinkRetry:
2838 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2839 (void **) &pSMBr);
2840 if (rc)
2841 return rc;
2842
2843 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002844 name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, toName,
2845 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002846 name_len++; /* trailing null */
2847 name_len *= 2;
2848
Steve French50c2f752007-07-13 00:33:32 +00002849 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002850 name_len = strnlen(toName, PATH_MAX);
2851 name_len++; /* trailing null */
2852 strncpy(pSMB->FileName, toName, name_len);
2853 }
2854 params = 6 + name_len;
2855 pSMB->MaxSetupCount = 0;
2856 pSMB->Reserved = 0;
2857 pSMB->Flags = 0;
2858 pSMB->Timeout = 0;
2859 pSMB->Reserved2 = 0;
2860 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002861 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002862 offset = param_offset + params;
2863
2864 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2865 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2866 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06002867 cifsConvertToUTF16((__le16 *) data_offset, fromName,
2868 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002869 name_len_target++; /* trailing null */
2870 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002871 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002872 name_len_target = strnlen(fromName, PATH_MAX);
2873 name_len_target++; /* trailing null */
2874 strncpy(data_offset, fromName, name_len_target);
2875 }
2876
2877 pSMB->MaxParameterCount = cpu_to_le16(2);
2878 /* BB find exact max on data count below from sess*/
2879 pSMB->MaxDataCount = cpu_to_le16(1000);
2880 pSMB->SetupCount = 1;
2881 pSMB->Reserved3 = 0;
2882 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2883 byte_count = 3 /* pad */ + params + name_len_target;
2884 pSMB->ParameterCount = cpu_to_le16(params);
2885 pSMB->TotalParameterCount = pSMB->ParameterCount;
2886 pSMB->DataCount = cpu_to_le16(name_len_target);
2887 pSMB->TotalDataCount = pSMB->DataCount;
2888 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2889 pSMB->DataOffset = cpu_to_le16(offset);
2890 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2891 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002892 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002893 pSMB->ByteCount = cpu_to_le16(byte_count);
2894 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2895 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002896 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002897 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002898 cFYI(1, "Send error in SetPathInfo (hard link) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002899
2900 cifs_buf_release(pSMB);
2901 if (rc == -EAGAIN)
2902 goto createHardLinkRetry;
2903
2904 return rc;
2905}
2906
2907int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002908CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchd6e906f2012-09-18 16:20:31 -07002909 const char *from_name, const char *to_name,
2910 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002911{
2912 int rc = 0;
2913 NT_RENAME_REQ *pSMB = NULL;
2914 RENAME_RSP *pSMBr = NULL;
2915 int bytes_returned;
2916 int name_len, name_len2;
2917 __u16 count;
Steve Frenchd6e906f2012-09-18 16:20:31 -07002918 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002919
Joe Perchesb6b38f72010-04-21 03:50:45 +00002920 cFYI(1, "In CIFSCreateHardLink");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002921winCreateHardLinkRetry:
2922
2923 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2924 (void **) &pSMBr);
2925 if (rc)
2926 return rc;
2927
2928 pSMB->SearchAttributes =
2929 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2930 ATTR_DIRECTORY);
2931 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2932 pSMB->ClusterCount = 0;
2933
2934 pSMB->BufferFormat = 0x04;
2935
2936 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2937 name_len =
Steve Frenchd6e906f2012-09-18 16:20:31 -07002938 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, from_name,
2939 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002940 name_len++; /* trailing null */
2941 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05002942
2943 /* protocol specifies ASCII buffer format (0x04) for unicode */
2944 pSMB->OldFileName[name_len] = 0x04;
2945 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002946 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002947 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Steve Frenchd6e906f2012-09-18 16:20:31 -07002948 to_name, PATH_MAX, cifs_sb->local_nls,
2949 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002950 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2951 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002952 } else { /* BB improve the check for buffer overruns BB */
Steve Frenchd6e906f2012-09-18 16:20:31 -07002953 name_len = strnlen(from_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002954 name_len++; /* trailing null */
Steve Frenchd6e906f2012-09-18 16:20:31 -07002955 strncpy(pSMB->OldFileName, from_name, name_len);
2956 name_len2 = strnlen(to_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002957 name_len2++; /* trailing null */
2958 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Steve Frenchd6e906f2012-09-18 16:20:31 -07002959 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002960 name_len2++; /* trailing null */
2961 name_len2++; /* signature byte */
2962 }
2963
2964 count = 1 /* string type byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002965 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002966 pSMB->ByteCount = cpu_to_le16(count);
2967
2968 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2969 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002970 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002971 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002972 cFYI(1, "Send error in hard link (NT rename) = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00002973
Linus Torvalds1da177e2005-04-16 15:20:36 -07002974 cifs_buf_release(pSMB);
2975 if (rc == -EAGAIN)
2976 goto winCreateHardLinkRetry;
2977
2978 return rc;
2979}
2980
2981int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002982CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04002983 const unsigned char *searchName, char **symlinkinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002984 const struct nls_table *nls_codepage)
2985{
2986/* SMB_QUERY_FILE_UNIX_LINK */
2987 TRANSACTION2_QPI_REQ *pSMB = NULL;
2988 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2989 int rc = 0;
2990 int bytes_returned;
2991 int name_len;
2992 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04002993 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002994
Joe Perchesb6b38f72010-04-21 03:50:45 +00002995 cFYI(1, "In QPathSymLinkInfo (Unix) for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002996
2997querySymLinkRetry:
2998 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2999 (void **) &pSMBr);
3000 if (rc)
3001 return rc;
3002
3003 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3004 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003005 cifs_strtoUTF16((__le16 *) pSMB->FileName, searchName,
3006 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003007 name_len++; /* trailing null */
3008 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003009 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003010 name_len = strnlen(searchName, PATH_MAX);
3011 name_len++; /* trailing null */
3012 strncpy(pSMB->FileName, searchName, name_len);
3013 }
3014
3015 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3016 pSMB->TotalDataCount = 0;
3017 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04003018 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003019 pSMB->MaxSetupCount = 0;
3020 pSMB->Reserved = 0;
3021 pSMB->Flags = 0;
3022 pSMB->Timeout = 0;
3023 pSMB->Reserved2 = 0;
3024 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003025 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003026 pSMB->DataCount = 0;
3027 pSMB->DataOffset = 0;
3028 pSMB->SetupCount = 1;
3029 pSMB->Reserved3 = 0;
3030 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3031 byte_count = params + 1 /* pad */ ;
3032 pSMB->TotalParameterCount = cpu_to_le16(params);
3033 pSMB->ParameterCount = pSMB->TotalParameterCount;
3034 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
3035 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003036 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003037 pSMB->ByteCount = cpu_to_le16(byte_count);
3038
3039 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3040 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3041 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003042 cFYI(1, "Send error in QuerySymLinkInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003043 } else {
3044 /* decode response */
3045
3046 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003047 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003048 if (rc || get_bcc(&pSMBr->hdr) < 2)
Jeff Layton460b9692009-04-30 07:17:56 -04003049 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003050 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00003051 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04003052 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003053
Jeff Layton460b9692009-04-30 07:17:56 -04003054 data_start = ((char *) &pSMBr->hdr.Protocol) +
3055 le16_to_cpu(pSMBr->t2.DataOffset);
3056
Steve French0e0d2cf2009-05-01 05:27:32 +00003057 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3058 is_unicode = true;
3059 else
3060 is_unicode = false;
3061
Steve French737b7582005-04-28 22:41:06 -07003062 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchacbbb762012-01-18 22:32:33 -06003063 *symlinkinfo = cifs_strndup_from_utf16(data_start,
3064 count, is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04003065 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04003066 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003067 }
3068 }
3069 cifs_buf_release(pSMB);
3070 if (rc == -EAGAIN)
3071 goto querySymLinkRetry;
3072 return rc;
3073}
3074
Steve Frenchc52a9552011-02-24 06:16:22 +00003075#ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL
3076/*
3077 * Recent Windows versions now create symlinks more frequently
3078 * and they use the "reparse point" mechanism below. We can of course
3079 * do symlinks nicely to Samba and other servers which support the
3080 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
3081 * "MF" symlinks optionally, but for recent Windows we really need to
3082 * reenable the code below and fix the cifs_symlink callers to handle this.
3083 * In the interim this code has been moved to its own config option so
3084 * it is not compiled in by default until callers fixed up and more tested.
3085 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003086int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003087CIFSSMBQueryReparseLinkInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003088 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00003089 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003090 const struct nls_table *nls_codepage)
3091{
3092 int rc = 0;
3093 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00003094 struct smb_com_transaction_ioctl_req *pSMB;
3095 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003096
Joe Perchesb6b38f72010-04-21 03:50:45 +00003097 cFYI(1, "In Windows reparse style QueryLink for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003098 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3099 (void **) &pSMBr);
3100 if (rc)
3101 return rc;
3102
3103 pSMB->TotalParameterCount = 0 ;
3104 pSMB->TotalDataCount = 0;
3105 pSMB->MaxParameterCount = cpu_to_le32(2);
3106 /* BB find exact data count max from sess structure BB */
Jeff Laytonc974bef2011-10-11 06:41:32 -04003107 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003108 pSMB->MaxSetupCount = 4;
3109 pSMB->Reserved = 0;
3110 pSMB->ParameterOffset = 0;
3111 pSMB->DataCount = 0;
3112 pSMB->DataOffset = 0;
3113 pSMB->SetupCount = 4;
3114 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
3115 pSMB->ParameterCount = pSMB->TotalParameterCount;
3116 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
3117 pSMB->IsFsctl = 1; /* FSCTL */
3118 pSMB->IsRootFlag = 0;
3119 pSMB->Fid = fid; /* file handle always le */
3120 pSMB->ByteCount = 0;
3121
3122 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3123 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3124 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003125 cFYI(1, "Send error in QueryReparseLinkInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003126 } else { /* decode response */
3127 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
3128 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
Jeff Layton820a8032011-05-04 08:05:26 -04003129 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
3130 /* BB also check enough total bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003131 rc = -EIO; /* bad smb */
Steve Frenchafe48c32009-05-02 05:25:46 +00003132 goto qreparse_out;
3133 }
3134 if (data_count && (data_count < 2048)) {
3135 char *end_of_smb = 2 /* sizeof byte count */ +
Jeff Layton820a8032011-05-04 08:05:26 -04003136 get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003137
Steve Frenchafe48c32009-05-02 05:25:46 +00003138 struct reparse_data *reparse_buf =
Steve French50c2f752007-07-13 00:33:32 +00003139 (struct reparse_data *)
3140 ((char *)&pSMBr->hdr.Protocol
3141 + data_offset);
Steve Frenchafe48c32009-05-02 05:25:46 +00003142 if ((char *)reparse_buf >= end_of_smb) {
3143 rc = -EIO;
3144 goto qreparse_out;
3145 }
3146 if ((reparse_buf->LinkNamesBuf +
3147 reparse_buf->TargetNameOffset +
3148 reparse_buf->TargetNameLen) > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003149 cFYI(1, "reparse buf beyond SMB");
Steve Frenchafe48c32009-05-02 05:25:46 +00003150 rc = -EIO;
3151 goto qreparse_out;
3152 }
Steve French50c2f752007-07-13 00:33:32 +00003153
Steve Frenchafe48c32009-05-02 05:25:46 +00003154 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3155 cifs_from_ucs2(symlinkinfo, (__le16 *)
Steve French50c2f752007-07-13 00:33:32 +00003156 (reparse_buf->LinkNamesBuf +
3157 reparse_buf->TargetNameOffset),
Steve Frenchafe48c32009-05-02 05:25:46 +00003158 buflen,
3159 reparse_buf->TargetNameLen,
3160 nls_codepage, 0);
3161 } else { /* ASCII names */
3162 strncpy(symlinkinfo,
3163 reparse_buf->LinkNamesBuf +
3164 reparse_buf->TargetNameOffset,
3165 min_t(const int, buflen,
3166 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003167 }
Steve Frenchafe48c32009-05-02 05:25:46 +00003168 } else {
3169 rc = -EIO;
Joe Perchesb6b38f72010-04-21 03:50:45 +00003170 cFYI(1, "Invalid return data count on "
3171 "get reparse info ioctl");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003172 }
Steve Frenchafe48c32009-05-02 05:25:46 +00003173 symlinkinfo[buflen] = 0; /* just in case so the caller
3174 does not go off the end of the buffer */
Joe Perchesb6b38f72010-04-21 03:50:45 +00003175 cFYI(1, "readlink result - %s", symlinkinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003176 }
Steve French989c7e52009-05-02 05:32:20 +00003177
Linus Torvalds1da177e2005-04-16 15:20:36 -07003178qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07003179 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003180
3181 /* Note: On -EAGAIN error only caller can retry on handle based calls
3182 since file handle passed in no longer valid */
3183
3184 return rc;
3185}
Steve Frenchc52a9552011-02-24 06:16:22 +00003186#endif /* CIFS_SYMLINK_EXPERIMENTAL */ /* BB temporarily unused */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003187
3188#ifdef CONFIG_CIFS_POSIX
3189
3190/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00003191static void cifs_convert_ace(posix_acl_xattr_entry *ace,
3192 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003193{
3194 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08003195 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
3196 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
3197 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesb6b38f72010-04-21 03:50:45 +00003198 /* cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003199
3200 return;
3201}
3202
3203/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00003204static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
3205 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003206{
3207 int size = 0;
3208 int i;
3209 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00003210 struct cifs_posix_ace *pACE;
3211 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
3212 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003213
3214 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
3215 return -EOPNOTSUPP;
3216
Steve French790fe572007-07-07 19:25:05 +00003217 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003218 count = le16_to_cpu(cifs_acl->access_entry_count);
3219 pACE = &cifs_acl->ace_array[0];
3220 size = sizeof(struct cifs_posix_acl);
3221 size += sizeof(struct cifs_posix_ace) * count;
3222 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003223 if (size_of_data_area < size) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003224 cFYI(1, "bad CIFS POSIX ACL size %d vs. %d",
3225 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003226 return -EINVAL;
3227 }
Steve French790fe572007-07-07 19:25:05 +00003228 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003229 count = le16_to_cpu(cifs_acl->access_entry_count);
3230 size = sizeof(struct cifs_posix_acl);
3231 size += sizeof(struct cifs_posix_ace) * count;
3232/* skip past access ACEs to get to default ACEs */
3233 pACE = &cifs_acl->ace_array[count];
3234 count = le16_to_cpu(cifs_acl->default_entry_count);
3235 size += sizeof(struct cifs_posix_ace) * count;
3236 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003237 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003238 return -EINVAL;
3239 } else {
3240 /* illegal type */
3241 return -EINVAL;
3242 }
3243
3244 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00003245 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00003246 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00003247 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003248 return -ERANGE;
3249 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08003250 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00003251 for (i = 0; i < count ; i++) {
3252 cifs_convert_ace(&local_acl->a_entries[i], pACE);
3253 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003254 }
3255 }
3256 return size;
3257}
3258
Steve French50c2f752007-07-13 00:33:32 +00003259static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
3260 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003261{
3262 __u16 rc = 0; /* 0 = ACL converted ok */
3263
Steve Frenchff7feac2005-11-15 16:45:16 -08003264 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
3265 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003266 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00003267 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003268 /* Probably no need to le convert -1 on any arch but can not hurt */
3269 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00003270 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08003271 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesb6b38f72010-04-21 03:50:45 +00003272 /*cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id);*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003273 return rc;
3274}
3275
3276/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00003277static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
3278 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003279{
3280 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00003281 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
3282 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003283 int count;
3284 int i;
3285
Steve French790fe572007-07-07 19:25:05 +00003286 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003287 return 0;
3288
3289 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesb6b38f72010-04-21 03:50:45 +00003290 cFYI(1, "setting acl with %d entries from buf of length %d and "
Steve French63135e02007-07-17 17:34:02 +00003291 "version of %d",
Joe Perchesb6b38f72010-04-21 03:50:45 +00003292 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00003293 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003294 cFYI(1, "unknown POSIX ACL version %d",
3295 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003296 return 0;
3297 }
3298 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00003299 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08003300 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00003301 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08003302 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003303 else {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003304 cFYI(1, "unknown ACL type %d", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003305 return 0;
3306 }
Steve French50c2f752007-07-13 00:33:32 +00003307 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003308 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
3309 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00003310 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003311 /* ACE not converted */
3312 break;
3313 }
3314 }
Steve French790fe572007-07-07 19:25:05 +00003315 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003316 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
3317 rc += sizeof(struct cifs_posix_acl);
3318 /* BB add check to make sure ACL does not overflow SMB */
3319 }
3320 return rc;
3321}
3322
3323int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003324CIFSSMBGetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003325 const unsigned char *searchName,
3326 char *acl_inf, const int buflen, const int acl_type,
3327 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003328{
3329/* SMB_QUERY_POSIX_ACL */
3330 TRANSACTION2_QPI_REQ *pSMB = NULL;
3331 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3332 int rc = 0;
3333 int bytes_returned;
3334 int name_len;
3335 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00003336
Joe Perchesb6b38f72010-04-21 03:50:45 +00003337 cFYI(1, "In GetPosixACL (Unix) for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003338
3339queryAclRetry:
3340 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3341 (void **) &pSMBr);
3342 if (rc)
3343 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003344
Linus Torvalds1da177e2005-04-16 15:20:36 -07003345 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3346 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003347 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3348 searchName, PATH_MAX, nls_codepage,
3349 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003350 name_len++; /* trailing null */
3351 name_len *= 2;
3352 pSMB->FileName[name_len] = 0;
3353 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00003354 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003355 name_len = strnlen(searchName, PATH_MAX);
3356 name_len++; /* trailing null */
3357 strncpy(pSMB->FileName, searchName, name_len);
3358 }
3359
3360 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3361 pSMB->TotalDataCount = 0;
3362 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00003363 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003364 pSMB->MaxDataCount = cpu_to_le16(4000);
3365 pSMB->MaxSetupCount = 0;
3366 pSMB->Reserved = 0;
3367 pSMB->Flags = 0;
3368 pSMB->Timeout = 0;
3369 pSMB->Reserved2 = 0;
3370 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003371 offsetof(struct smb_com_transaction2_qpi_req,
3372 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003373 pSMB->DataCount = 0;
3374 pSMB->DataOffset = 0;
3375 pSMB->SetupCount = 1;
3376 pSMB->Reserved3 = 0;
3377 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3378 byte_count = params + 1 /* pad */ ;
3379 pSMB->TotalParameterCount = cpu_to_le16(params);
3380 pSMB->ParameterCount = pSMB->TotalParameterCount;
3381 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
3382 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003383 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003384 pSMB->ByteCount = cpu_to_le16(byte_count);
3385
3386 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3387 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003388 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003389 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003390 cFYI(1, "Send error in Query POSIX ACL = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003391 } else {
3392 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00003393
Linus Torvalds1da177e2005-04-16 15:20:36 -07003394 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003395 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003396 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003397 rc = -EIO; /* bad smb */
3398 else {
3399 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3400 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3401 rc = cifs_copy_posix_acl(acl_inf,
3402 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00003403 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003404 }
3405 }
3406 cifs_buf_release(pSMB);
3407 if (rc == -EAGAIN)
3408 goto queryAclRetry;
3409 return rc;
3410}
3411
3412int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003413CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003414 const unsigned char *fileName,
3415 const char *local_acl, const int buflen,
3416 const int acl_type,
3417 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003418{
3419 struct smb_com_transaction2_spi_req *pSMB = NULL;
3420 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3421 char *parm_data;
3422 int name_len;
3423 int rc = 0;
3424 int bytes_returned = 0;
3425 __u16 params, byte_count, data_count, param_offset, offset;
3426
Joe Perchesb6b38f72010-04-21 03:50:45 +00003427 cFYI(1, "In SetPosixACL (Unix) for path %s", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003428setAclRetry:
3429 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003430 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003431 if (rc)
3432 return rc;
3433 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3434 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003435 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
3436 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003437 name_len++; /* trailing null */
3438 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003439 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003440 name_len = strnlen(fileName, PATH_MAX);
3441 name_len++; /* trailing null */
3442 strncpy(pSMB->FileName, fileName, name_len);
3443 }
3444 params = 6 + name_len;
3445 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003446 /* BB find max SMB size from sess */
3447 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003448 pSMB->MaxSetupCount = 0;
3449 pSMB->Reserved = 0;
3450 pSMB->Flags = 0;
3451 pSMB->Timeout = 0;
3452 pSMB->Reserved2 = 0;
3453 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003454 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003455 offset = param_offset + params;
3456 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
3457 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3458
3459 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00003460 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003461
Steve French790fe572007-07-07 19:25:05 +00003462 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003463 rc = -EOPNOTSUPP;
3464 goto setACLerrorExit;
3465 }
3466 pSMB->DataOffset = cpu_to_le16(offset);
3467 pSMB->SetupCount = 1;
3468 pSMB->Reserved3 = 0;
3469 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3470 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
3471 byte_count = 3 /* pad */ + params + data_count;
3472 pSMB->DataCount = cpu_to_le16(data_count);
3473 pSMB->TotalDataCount = pSMB->DataCount;
3474 pSMB->ParameterCount = cpu_to_le16(params);
3475 pSMB->TotalParameterCount = pSMB->ParameterCount;
3476 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003477 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003478 pSMB->ByteCount = cpu_to_le16(byte_count);
3479 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003480 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003481 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003482 cFYI(1, "Set POSIX ACL returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003483
3484setACLerrorExit:
3485 cifs_buf_release(pSMB);
3486 if (rc == -EAGAIN)
3487 goto setAclRetry;
3488 return rc;
3489}
3490
Steve Frenchf654bac2005-04-28 22:41:04 -07003491/* BB fix tabs in this function FIXME BB */
3492int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003493CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00003494 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07003495{
Steve French50c2f752007-07-13 00:33:32 +00003496 int rc = 0;
3497 struct smb_t2_qfi_req *pSMB = NULL;
3498 struct smb_t2_qfi_rsp *pSMBr = NULL;
3499 int bytes_returned;
3500 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07003501
Joe Perchesb6b38f72010-04-21 03:50:45 +00003502 cFYI(1, "In GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00003503 if (tcon == NULL)
3504 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07003505
3506GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003507 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3508 (void **) &pSMBr);
3509 if (rc)
3510 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003511
Steve Frenchad7a2922008-02-07 23:25:02 +00003512 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003513 pSMB->t2.TotalDataCount = 0;
3514 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3515 /* BB find exact max data count below from sess structure BB */
3516 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3517 pSMB->t2.MaxSetupCount = 0;
3518 pSMB->t2.Reserved = 0;
3519 pSMB->t2.Flags = 0;
3520 pSMB->t2.Timeout = 0;
3521 pSMB->t2.Reserved2 = 0;
3522 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3523 Fid) - 4);
3524 pSMB->t2.DataCount = 0;
3525 pSMB->t2.DataOffset = 0;
3526 pSMB->t2.SetupCount = 1;
3527 pSMB->t2.Reserved3 = 0;
3528 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3529 byte_count = params + 1 /* pad */ ;
3530 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3531 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3532 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3533 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003534 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003535 inc_rfc1001_len(pSMB, byte_count);
Steve French790fe572007-07-07 19:25:05 +00003536 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003537
Steve French790fe572007-07-07 19:25:05 +00003538 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3539 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3540 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003541 cFYI(1, "error %d in GetExtAttr", rc);
Steve French790fe572007-07-07 19:25:05 +00003542 } else {
3543 /* decode response */
3544 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003545 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003546 if (rc || get_bcc(&pSMBr->hdr) < 2)
Steve French790fe572007-07-07 19:25:05 +00003547 /* If rc should we check for EOPNOSUPP and
3548 disable the srvino flag? or in caller? */
3549 rc = -EIO; /* bad smb */
3550 else {
3551 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3552 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3553 struct file_chattr_info *pfinfo;
3554 /* BB Do we need a cast or hash here ? */
3555 if (count != 16) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003556 cFYI(1, "Illegal size ret in GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00003557 rc = -EIO;
3558 goto GetExtAttrOut;
3559 }
3560 pfinfo = (struct file_chattr_info *)
3561 (data_offset + (char *) &pSMBr->hdr.Protocol);
3562 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003563 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003564 }
3565 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003566GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003567 cifs_buf_release(pSMB);
3568 if (rc == -EAGAIN)
3569 goto GetExtAttrRetry;
3570 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003571}
3572
Steve Frenchf654bac2005-04-28 22:41:04 -07003573#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003574
Jeff Layton79df1ba2010-12-06 12:52:08 -05003575#ifdef CONFIG_CIFS_ACL
3576/*
3577 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3578 * all NT TRANSACTS that we init here have total parm and data under about 400
3579 * bytes (to fit in small cifs buffer size), which is the case so far, it
3580 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3581 * returned setup area) and MaxParameterCount (returned parms size) must be set
3582 * by caller
3583 */
3584static int
3585smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French96daf2b2011-05-27 04:34:02 +00003586 const int parm_len, struct cifs_tcon *tcon,
Jeff Layton79df1ba2010-12-06 12:52:08 -05003587 void **ret_buf)
3588{
3589 int rc;
3590 __u32 temp_offset;
3591 struct smb_com_ntransact_req *pSMB;
3592
3593 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3594 (void **)&pSMB);
3595 if (rc)
3596 return rc;
3597 *ret_buf = (void *)pSMB;
3598 pSMB->Reserved = 0;
3599 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3600 pSMB->TotalDataCount = 0;
Jeff Laytonc974bef2011-10-11 06:41:32 -04003601 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003602 pSMB->ParameterCount = pSMB->TotalParameterCount;
3603 pSMB->DataCount = pSMB->TotalDataCount;
3604 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3605 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3606 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3607 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3608 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3609 pSMB->SubCommand = cpu_to_le16(sub_command);
3610 return 0;
3611}
3612
3613static int
3614validate_ntransact(char *buf, char **ppparm, char **ppdata,
3615 __u32 *pparmlen, __u32 *pdatalen)
3616{
3617 char *end_of_smb;
3618 __u32 data_count, data_offset, parm_count, parm_offset;
3619 struct smb_com_ntransact_rsp *pSMBr;
Jeff Layton820a8032011-05-04 08:05:26 -04003620 u16 bcc;
Jeff Layton79df1ba2010-12-06 12:52:08 -05003621
3622 *pdatalen = 0;
3623 *pparmlen = 0;
3624
3625 if (buf == NULL)
3626 return -EINVAL;
3627
3628 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3629
Jeff Layton820a8032011-05-04 08:05:26 -04003630 bcc = get_bcc(&pSMBr->hdr);
3631 end_of_smb = 2 /* sizeof byte count */ + bcc +
Jeff Layton79df1ba2010-12-06 12:52:08 -05003632 (char *)&pSMBr->ByteCount;
3633
3634 data_offset = le32_to_cpu(pSMBr->DataOffset);
3635 data_count = le32_to_cpu(pSMBr->DataCount);
3636 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3637 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3638
3639 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3640 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3641
3642 /* should we also check that parm and data areas do not overlap? */
3643 if (*ppparm > end_of_smb) {
3644 cFYI(1, "parms start after end of smb");
3645 return -EINVAL;
3646 } else if (parm_count + *ppparm > end_of_smb) {
3647 cFYI(1, "parm end after end of smb");
3648 return -EINVAL;
3649 } else if (*ppdata > end_of_smb) {
3650 cFYI(1, "data starts after end of smb");
3651 return -EINVAL;
3652 } else if (data_count + *ppdata > end_of_smb) {
3653 cFYI(1, "data %p + count %d (%p) past smb end %p start %p",
3654 *ppdata, data_count, (data_count + *ppdata),
3655 end_of_smb, pSMBr);
3656 return -EINVAL;
Jeff Layton820a8032011-05-04 08:05:26 -04003657 } else if (parm_count + data_count > bcc) {
Jeff Layton79df1ba2010-12-06 12:52:08 -05003658 cFYI(1, "parm count and data count larger than SMB");
3659 return -EINVAL;
3660 }
3661 *pdatalen = data_count;
3662 *pparmlen = parm_count;
3663 return 0;
3664}
3665
Steve French0a4b92c2006-01-12 15:44:21 -08003666/* Get Security Descriptor (by handle) from remote server for a file or dir */
3667int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003668CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003669 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003670{
3671 int rc = 0;
3672 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003673 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003674 struct kvec iov[1];
3675
Joe Perchesb6b38f72010-04-21 03:50:45 +00003676 cFYI(1, "GetCifsACL");
Steve French0a4b92c2006-01-12 15:44:21 -08003677
Steve French630f3f0c2007-10-25 21:17:17 +00003678 *pbuflen = 0;
3679 *acl_inf = NULL;
3680
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003681 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003682 8 /* parm len */, tcon, (void **) &pSMB);
3683 if (rc)
3684 return rc;
3685
3686 pSMB->MaxParameterCount = cpu_to_le32(4);
3687 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3688 pSMB->MaxSetupCount = 0;
3689 pSMB->Fid = fid; /* file handle always le */
3690 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3691 CIFS_ACL_DACL);
3692 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003693 inc_rfc1001_len(pSMB, 11);
Steve French0a4b92c2006-01-12 15:44:21 -08003694 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003695 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French0a4b92c2006-01-12 15:44:21 -08003696
Steve Frencha761ac52007-10-18 21:45:27 +00003697 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Jeff Layton77499812011-01-11 07:24:23 -05003698 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003699 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Steve French0a4b92c2006-01-12 15:44:21 -08003700 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003701 cFYI(1, "Send error in QuerySecDesc = %d", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08003702 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003703 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003704 __u32 parm_len;
3705 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003706 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003707 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003708
3709/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003710 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003711 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003712 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003713 goto qsec_out;
3714 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3715
Joe Perchesb6b38f72010-04-21 03:50:45 +00003716 cFYI(1, "smb %p parm %p data %p", pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08003717
3718 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3719 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003720 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003721 goto qsec_out;
3722 }
3723
3724/* BB check that data area is minimum length and as big as acl_len */
3725
Steve Frenchaf6f4612007-10-16 18:40:37 +00003726 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003727 if (acl_len != *pbuflen) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003728 cERROR(1, "acl length %d does not match %d",
3729 acl_len, *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003730 if (*pbuflen > acl_len)
3731 *pbuflen = acl_len;
3732 }
Steve French0a4b92c2006-01-12 15:44:21 -08003733
Steve French630f3f0c2007-10-25 21:17:17 +00003734 /* check if buffer is big enough for the acl
3735 header followed by the smallest SID */
3736 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3737 (*pbuflen >= 64 * 1024)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003738 cERROR(1, "bad acl length %d", *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003739 rc = -EINVAL;
3740 *pbuflen = 0;
3741 } else {
3742 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3743 if (*acl_inf == NULL) {
3744 *pbuflen = 0;
3745 rc = -ENOMEM;
3746 }
3747 memcpy(*acl_inf, pdata, *pbuflen);
3748 }
Steve French0a4b92c2006-01-12 15:44:21 -08003749 }
3750qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003751 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003752 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003753 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003754 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003755/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003756 return rc;
3757}
Steve French97837582007-12-31 07:47:21 +00003758
3759int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003760CIFSSMBSetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003761 struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
Steve French97837582007-12-31 07:47:21 +00003762{
3763 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3764 int rc = 0;
3765 int bytes_returned = 0;
3766 SET_SEC_DESC_REQ *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003767 void *pSMBr;
Steve French97837582007-12-31 07:47:21 +00003768
3769setCifsAclRetry:
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003770 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, &pSMBr);
Steve French97837582007-12-31 07:47:21 +00003771 if (rc)
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003772 return rc;
Steve French97837582007-12-31 07:47:21 +00003773
3774 pSMB->MaxSetupCount = 0;
3775 pSMB->Reserved = 0;
3776
3777 param_count = 8;
3778 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3779 data_count = acllen;
3780 data_offset = param_offset + param_count;
3781 byte_count = 3 /* pad */ + param_count;
3782
3783 pSMB->DataCount = cpu_to_le32(data_count);
3784 pSMB->TotalDataCount = pSMB->DataCount;
3785 pSMB->MaxParameterCount = cpu_to_le32(4);
3786 pSMB->MaxDataCount = cpu_to_le32(16384);
3787 pSMB->ParameterCount = cpu_to_le32(param_count);
3788 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3789 pSMB->TotalParameterCount = pSMB->ParameterCount;
3790 pSMB->DataOffset = cpu_to_le32(data_offset);
3791 pSMB->SetupCount = 0;
3792 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3793 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3794
3795 pSMB->Fid = fid; /* file handle always le */
3796 pSMB->Reserved2 = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003797 pSMB->AclFlags = cpu_to_le32(aclflag);
Steve French97837582007-12-31 07:47:21 +00003798
3799 if (pntsd && acllen) {
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003800 memcpy((char *)pSMBr + offsetof(struct smb_hdr, Protocol) +
3801 data_offset, pntsd, acllen);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003802 inc_rfc1001_len(pSMB, byte_count + data_count);
Steve French97837582007-12-31 07:47:21 +00003803 } else
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003804 inc_rfc1001_len(pSMB, byte_count);
Steve French97837582007-12-31 07:47:21 +00003805
3806 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3807 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3808
Joe Perchesb6b38f72010-04-21 03:50:45 +00003809 cFYI(1, "SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00003810 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003811 cFYI(1, "Set CIFS ACL returned %d", rc);
Steve French97837582007-12-31 07:47:21 +00003812 cifs_buf_release(pSMB);
3813
3814 if (rc == -EAGAIN)
3815 goto setCifsAclRetry;
3816
3817 return (rc);
3818}
3819
Jeff Layton79df1ba2010-12-06 12:52:08 -05003820#endif /* CONFIG_CIFS_ACL */
Steve French0a4b92c2006-01-12 15:44:21 -08003821
Steve French6b8edfe2005-08-23 20:26:03 -07003822/* Legacy Query Path Information call for lookup to old servers such
3823 as Win9x/WinME */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003824int
3825SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon,
3826 const char *search_name, FILE_ALL_INFO *data,
3827 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003828{
Steve Frenchad7a2922008-02-07 23:25:02 +00003829 QUERY_INFORMATION_REQ *pSMB;
3830 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003831 int rc = 0;
3832 int bytes_returned;
3833 int name_len;
3834
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003835 cFYI(1, "In SMBQPath path %s", search_name);
Steve French6b8edfe2005-08-23 20:26:03 -07003836QInfRetry:
3837 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003838 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003839 if (rc)
3840 return rc;
3841
3842 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3843 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003844 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003845 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06003846 remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003847 name_len++; /* trailing null */
3848 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003849 } else {
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003850 name_len = strnlen(search_name, PATH_MAX);
Steve French6b8edfe2005-08-23 20:26:03 -07003851 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003852 strncpy(pSMB->FileName, search_name, name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07003853 }
3854 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003855 name_len++; /* account for buffer type byte */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003856 inc_rfc1001_len(pSMB, (__u16)name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07003857 pSMB->ByteCount = cpu_to_le16(name_len);
3858
3859 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003860 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003861 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003862 cFYI(1, "Send error in QueryInfo = %d", rc);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003863 } else if (data) {
Steve French1bd5bbc2006-09-28 03:35:57 +00003864 struct timespec ts;
3865 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00003866
3867 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003868 /* BB FIXME - add time zone adjustment BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003869 memset(data, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003870 ts.tv_nsec = 0;
3871 ts.tv_sec = time;
3872 /* decode time fields */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003873 data->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
3874 data->LastWriteTime = data->ChangeTime;
3875 data->LastAccessTime = 0;
3876 data->AllocationSize =
Steve French70ca7342005-09-22 16:32:06 -07003877 cpu_to_le64(le32_to_cpu(pSMBr->size));
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003878 data->EndOfFile = data->AllocationSize;
3879 data->Attributes =
Steve French70ca7342005-09-22 16:32:06 -07003880 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003881 } else
3882 rc = -EIO; /* bad buffer passed in */
3883
3884 cifs_buf_release(pSMB);
3885
3886 if (rc == -EAGAIN)
3887 goto QInfRetry;
3888
3889 return rc;
3890}
3891
Jeff Laytonbcd53572010-02-12 07:44:16 -05003892int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003893CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonbcd53572010-02-12 07:44:16 -05003894 u16 netfid, FILE_ALL_INFO *pFindData)
3895{
3896 struct smb_t2_qfi_req *pSMB = NULL;
3897 struct smb_t2_qfi_rsp *pSMBr = NULL;
3898 int rc = 0;
3899 int bytes_returned;
3900 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07003901
Jeff Laytonbcd53572010-02-12 07:44:16 -05003902QFileInfoRetry:
3903 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3904 (void **) &pSMBr);
3905 if (rc)
3906 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07003907
Jeff Laytonbcd53572010-02-12 07:44:16 -05003908 params = 2 /* level */ + 2 /* fid */;
3909 pSMB->t2.TotalDataCount = 0;
3910 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3911 /* BB find exact max data count below from sess structure BB */
3912 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3913 pSMB->t2.MaxSetupCount = 0;
3914 pSMB->t2.Reserved = 0;
3915 pSMB->t2.Flags = 0;
3916 pSMB->t2.Timeout = 0;
3917 pSMB->t2.Reserved2 = 0;
3918 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3919 Fid) - 4);
3920 pSMB->t2.DataCount = 0;
3921 pSMB->t2.DataOffset = 0;
3922 pSMB->t2.SetupCount = 1;
3923 pSMB->t2.Reserved3 = 0;
3924 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3925 byte_count = params + 1 /* pad */ ;
3926 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3927 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3928 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3929 pSMB->Pad = 0;
3930 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003931 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003932
3933 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3934 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3935 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00003936 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003937 } else { /* decode response */
3938 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3939
3940 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3941 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04003942 else if (get_bcc(&pSMBr->hdr) < 40)
Jeff Laytonbcd53572010-02-12 07:44:16 -05003943 rc = -EIO; /* bad smb */
3944 else if (pFindData) {
3945 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3946 memcpy((char *) pFindData,
3947 (char *) &pSMBr->hdr.Protocol +
3948 data_offset, sizeof(FILE_ALL_INFO));
3949 } else
3950 rc = -ENOMEM;
3951 }
3952 cifs_buf_release(pSMB);
3953 if (rc == -EAGAIN)
3954 goto QFileInfoRetry;
3955
3956 return rc;
3957}
Steve French6b8edfe2005-08-23 20:26:03 -07003958
Linus Torvalds1da177e2005-04-16 15:20:36 -07003959int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003960CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003961 const char *search_name, FILE_ALL_INFO *data,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003962 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003963 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003964{
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003965 /* level 263 SMB_QUERY_FILE_ALL_INFO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003966 TRANSACTION2_QPI_REQ *pSMB = NULL;
3967 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3968 int rc = 0;
3969 int bytes_returned;
3970 int name_len;
3971 __u16 params, byte_count;
3972
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003973 /* cFYI(1, "In QPathInfo path %s", search_name); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003974QPathInfoRetry:
3975 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3976 (void **) &pSMBr);
3977 if (rc)
3978 return rc;
3979
3980 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3981 name_len =
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003982 cifsConvertToUTF16((__le16 *) pSMB->FileName, search_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06003983 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003984 name_len++; /* trailing null */
3985 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003986 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003987 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003988 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003989 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003990 }
3991
Steve French50c2f752007-07-13 00:33:32 +00003992 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003993 pSMB->TotalDataCount = 0;
3994 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003995 /* BB find exact max SMB PDU from sess structure BB */
3996 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003997 pSMB->MaxSetupCount = 0;
3998 pSMB->Reserved = 0;
3999 pSMB->Flags = 0;
4000 pSMB->Timeout = 0;
4001 pSMB->Reserved2 = 0;
4002 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004003 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004004 pSMB->DataCount = 0;
4005 pSMB->DataOffset = 0;
4006 pSMB->SetupCount = 1;
4007 pSMB->Reserved3 = 0;
4008 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4009 byte_count = params + 1 /* pad */ ;
4010 pSMB->TotalParameterCount = cpu_to_le16(params);
4011 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00004012 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004013 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
4014 else
4015 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004016 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004017 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004018 pSMB->ByteCount = cpu_to_le16(byte_count);
4019
4020 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4021 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4022 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004023 cFYI(1, "Send error in QPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004024 } else { /* decode response */
4025 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4026
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004027 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4028 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004029 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004030 rc = -EIO; /* bad smb */
Jeff Layton820a8032011-05-04 08:05:26 -04004031 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
Steve French50c2f752007-07-13 00:33:32 +00004032 rc = -EIO; /* 24 or 26 expected but we do not read
4033 last field */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004034 else if (data) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004035 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004036 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00004037
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004038 /*
4039 * On legacy responses we do not read the last field,
4040 * EAsize, fortunately since it varies by subdialect and
4041 * also note it differs on Set vs Get, ie two bytes or 4
4042 * bytes depending but we don't care here.
4043 */
Steve Frenchad7a2922008-02-07 23:25:02 +00004044 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004045 size = sizeof(FILE_INFO_STANDARD);
4046 else
4047 size = sizeof(FILE_ALL_INFO);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004048 memcpy((char *) data, (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004049 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004050 } else
4051 rc = -ENOMEM;
4052 }
4053 cifs_buf_release(pSMB);
4054 if (rc == -EAGAIN)
4055 goto QPathInfoRetry;
4056
4057 return rc;
4058}
4059
4060int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004061CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004062 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
4063{
4064 struct smb_t2_qfi_req *pSMB = NULL;
4065 struct smb_t2_qfi_rsp *pSMBr = NULL;
4066 int rc = 0;
4067 int bytes_returned;
4068 __u16 params, byte_count;
4069
4070UnixQFileInfoRetry:
4071 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4072 (void **) &pSMBr);
4073 if (rc)
4074 return rc;
4075
4076 params = 2 /* level */ + 2 /* fid */;
4077 pSMB->t2.TotalDataCount = 0;
4078 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4079 /* BB find exact max data count below from sess structure BB */
4080 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4081 pSMB->t2.MaxSetupCount = 0;
4082 pSMB->t2.Reserved = 0;
4083 pSMB->t2.Flags = 0;
4084 pSMB->t2.Timeout = 0;
4085 pSMB->t2.Reserved2 = 0;
4086 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4087 Fid) - 4);
4088 pSMB->t2.DataCount = 0;
4089 pSMB->t2.DataOffset = 0;
4090 pSMB->t2.SetupCount = 1;
4091 pSMB->t2.Reserved3 = 0;
4092 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4093 byte_count = params + 1 /* pad */ ;
4094 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4095 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4096 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4097 pSMB->Pad = 0;
4098 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004099 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004100
4101 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4102 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4103 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00004104 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004105 } else { /* decode response */
4106 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4107
Jeff Layton820a8032011-05-04 08:05:26 -04004108 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004109 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response. "
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004110 "Unix Extensions can be disabled on mount "
Steve Frenchf19159d2010-04-21 04:12:10 +00004111 "by specifying the nosfu mount option.");
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004112 rc = -EIO; /* bad smb */
4113 } else {
4114 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4115 memcpy((char *) pFindData,
4116 (char *) &pSMBr->hdr.Protocol +
4117 data_offset,
4118 sizeof(FILE_UNIX_BASIC_INFO));
4119 }
4120 }
4121
4122 cifs_buf_release(pSMB);
4123 if (rc == -EAGAIN)
4124 goto UnixQFileInfoRetry;
4125
4126 return rc;
4127}
4128
4129int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004130CIFSSMBUnixQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004131 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00004132 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07004133 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004134{
4135/* SMB_QUERY_FILE_UNIX_BASIC */
4136 TRANSACTION2_QPI_REQ *pSMB = NULL;
4137 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4138 int rc = 0;
4139 int bytes_returned = 0;
4140 int name_len;
4141 __u16 params, byte_count;
4142
Joe Perchesb6b38f72010-04-21 03:50:45 +00004143 cFYI(1, "In QPathInfo (Unix) the path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004144UnixQPathInfoRetry:
4145 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4146 (void **) &pSMBr);
4147 if (rc)
4148 return rc;
4149
4150 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4151 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004152 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4153 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004154 name_len++; /* trailing null */
4155 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004156 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004157 name_len = strnlen(searchName, PATH_MAX);
4158 name_len++; /* trailing null */
4159 strncpy(pSMB->FileName, searchName, name_len);
4160 }
4161
Steve French50c2f752007-07-13 00:33:32 +00004162 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004163 pSMB->TotalDataCount = 0;
4164 pSMB->MaxParameterCount = cpu_to_le16(2);
4165 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00004166 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004167 pSMB->MaxSetupCount = 0;
4168 pSMB->Reserved = 0;
4169 pSMB->Flags = 0;
4170 pSMB->Timeout = 0;
4171 pSMB->Reserved2 = 0;
4172 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004173 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004174 pSMB->DataCount = 0;
4175 pSMB->DataOffset = 0;
4176 pSMB->SetupCount = 1;
4177 pSMB->Reserved3 = 0;
4178 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4179 byte_count = params + 1 /* pad */ ;
4180 pSMB->TotalParameterCount = cpu_to_le16(params);
4181 pSMB->ParameterCount = pSMB->TotalParameterCount;
4182 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4183 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004184 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004185 pSMB->ByteCount = cpu_to_le16(byte_count);
4186
4187 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4188 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4189 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004190 cFYI(1, "Send error in QPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004191 } else { /* decode response */
4192 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4193
Jeff Layton820a8032011-05-04 08:05:26 -04004194 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004195 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response. "
Steve French1e71f252007-09-20 15:30:07 +00004196 "Unix Extensions can be disabled on mount "
Joe Perchesb6b38f72010-04-21 03:50:45 +00004197 "by specifying the nosfu mount option.");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004198 rc = -EIO; /* bad smb */
4199 } else {
4200 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4201 memcpy((char *) pFindData,
4202 (char *) &pSMBr->hdr.Protocol +
4203 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00004204 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004205 }
4206 }
4207 cifs_buf_release(pSMB);
4208 if (rc == -EAGAIN)
4209 goto UnixQPathInfoRetry;
4210
4211 return rc;
4212}
4213
Linus Torvalds1da177e2005-04-16 15:20:36 -07004214/* xid, tcon, searchName and codepage are input parms, rest are returned */
4215int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004216CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004217 const char *searchName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004218 const struct nls_table *nls_codepage,
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004219 __u16 *pnetfid, __u16 search_flags,
Steve French50c2f752007-07-13 00:33:32 +00004220 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004221{
4222/* level 257 SMB_ */
4223 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
4224 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004225 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004226 int rc = 0;
4227 int bytes_returned = 0;
4228 int name_len;
4229 __u16 params, byte_count;
4230
Joe Perchesb6b38f72010-04-21 03:50:45 +00004231 cFYI(1, "In FindFirst for %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004232
4233findFirstRetry:
4234 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4235 (void **) &pSMBr);
4236 if (rc)
4237 return rc;
4238
4239 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4240 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004241 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4242 PATH_MAX, nls_codepage, remap);
Steve French737b7582005-04-28 22:41:06 -07004243 /* We can not add the asterik earlier in case
4244 it got remapped to 0xF03A as if it were part of the
4245 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004246 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07004247 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07004248 pSMB->FileName[name_len+1] = 0;
4249 pSMB->FileName[name_len+2] = '*';
4250 pSMB->FileName[name_len+3] = 0;
4251 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004252 pSMB->FileName[name_len] = 0; /* null terminate just in case */
4253 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07004254 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004255 } else { /* BB add check for overrun of SMB buf BB */
4256 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004257/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00004258 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004259 free buffer exit; BB */
4260 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07004261 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07004262 pSMB->FileName[name_len+1] = '*';
4263 pSMB->FileName[name_len+2] = 0;
4264 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004265 }
4266
4267 params = 12 + name_len /* includes null */ ;
4268 pSMB->TotalDataCount = 0; /* no EAs */
4269 pSMB->MaxParameterCount = cpu_to_le16(10);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004270 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004271 pSMB->MaxSetupCount = 0;
4272 pSMB->Reserved = 0;
4273 pSMB->Flags = 0;
4274 pSMB->Timeout = 0;
4275 pSMB->Reserved2 = 0;
4276 byte_count = params + 1 /* pad */ ;
4277 pSMB->TotalParameterCount = cpu_to_le16(params);
4278 pSMB->ParameterCount = pSMB->TotalParameterCount;
4279 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00004280 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
4281 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004282 pSMB->DataCount = 0;
4283 pSMB->DataOffset = 0;
4284 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
4285 pSMB->Reserved3 = 0;
4286 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
4287 pSMB->SearchAttributes =
4288 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
4289 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00004290 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004291 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004292 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4293
4294 /* BB what should we set StorageType to? Does it matter? BB */
4295 pSMB->SearchStorageType = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004296 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004297 pSMB->ByteCount = cpu_to_le16(byte_count);
4298
4299 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4300 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004301 cifs_stats_inc(&tcon->stats.cifs_stats.num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004302
Steve French88274812006-03-09 22:21:45 +00004303 if (rc) {/* BB add logic to retry regular search if Unix search
4304 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004305 /* BB Add code to handle unsupported level rc */
Joe Perchesb6b38f72010-04-21 03:50:45 +00004306 cFYI(1, "Error in FindFirst = %d", rc);
Steve French1982c342005-08-17 12:38:22 -07004307
Steve French88274812006-03-09 22:21:45 +00004308 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004309
4310 /* BB eventually could optimize out free and realloc of buf */
4311 /* for this case */
4312 if (rc == -EAGAIN)
4313 goto findFirstRetry;
4314 } else { /* decode response */
4315 /* BB remember to free buffer if error BB */
4316 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00004317 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004318 unsigned int lnoff;
4319
Linus Torvalds1da177e2005-04-16 15:20:36 -07004320 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004321 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004322 else
Steve French4b18f2a2008-04-29 00:06:05 +00004323 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004324
4325 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004326 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00004327 psrch_inf->srch_entries_start =
4328 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004329 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004330 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
4331 le16_to_cpu(pSMBr->t2.ParameterOffset));
4332
Steve French790fe572007-07-07 19:25:05 +00004333 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004334 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004335 else
Steve French4b18f2a2008-04-29 00:06:05 +00004336 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004337
Steve French50c2f752007-07-13 00:33:32 +00004338 psrch_inf->entries_in_buffer =
4339 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00004340 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004341 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004342 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004343 if (CIFSMaxBufSize < lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004344 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00004345 psrch_inf->last_entry = NULL;
4346 return rc;
4347 }
4348
Steve French0752f152008-10-07 20:03:33 +00004349 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00004350 lnoff;
4351
Linus Torvalds1da177e2005-04-16 15:20:36 -07004352 *pnetfid = parms->SearchHandle;
4353 } else {
4354 cifs_buf_release(pSMB);
4355 }
4356 }
4357
4358 return rc;
4359}
4360
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004361int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
4362 __u16 searchHandle, __u16 search_flags,
4363 struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004364{
4365 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
4366 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004367 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004368 char *response_data;
4369 int rc = 0;
Jeff Layton9438fab2011-08-23 07:21:28 -04004370 int bytes_returned;
4371 unsigned int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004372 __u16 params, byte_count;
4373
Joe Perchesb6b38f72010-04-21 03:50:45 +00004374 cFYI(1, "In FindNext");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004375
Steve French4b18f2a2008-04-29 00:06:05 +00004376 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004377 return -ENOENT;
4378
4379 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4380 (void **) &pSMBr);
4381 if (rc)
4382 return rc;
4383
Steve French50c2f752007-07-13 00:33:32 +00004384 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004385 byte_count = 0;
4386 pSMB->TotalDataCount = 0; /* no EAs */
4387 pSMB->MaxParameterCount = cpu_to_le16(8);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004388 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004389 pSMB->MaxSetupCount = 0;
4390 pSMB->Reserved = 0;
4391 pSMB->Flags = 0;
4392 pSMB->Timeout = 0;
4393 pSMB->Reserved2 = 0;
4394 pSMB->ParameterOffset = cpu_to_le16(
4395 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
4396 pSMB->DataCount = 0;
4397 pSMB->DataOffset = 0;
4398 pSMB->SetupCount = 1;
4399 pSMB->Reserved3 = 0;
4400 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
4401 pSMB->SearchHandle = searchHandle; /* always kept as le */
4402 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00004403 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004404 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4405 pSMB->ResumeKey = psrch_inf->resume_key;
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004406 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004407
4408 name_len = psrch_inf->resume_name_len;
4409 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00004410 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004411 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
4412 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07004413 /* 14 byte parm len above enough for 2 byte null terminator */
4414 pSMB->ResumeFileName[name_len] = 0;
4415 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004416 } else {
4417 rc = -EINVAL;
4418 goto FNext2_err_exit;
4419 }
4420 byte_count = params + 1 /* pad */ ;
4421 pSMB->TotalParameterCount = cpu_to_le16(params);
4422 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004423 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004424 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004425
Linus Torvalds1da177e2005-04-16 15:20:36 -07004426 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4427 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004428 cifs_stats_inc(&tcon->stats.cifs_stats.num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004429 if (rc) {
4430 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00004431 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07004432 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00004433 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004434 } else
Joe Perchesb6b38f72010-04-21 03:50:45 +00004435 cFYI(1, "FindNext returned = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004436 } else { /* decode response */
4437 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00004438
Steve French790fe572007-07-07 19:25:05 +00004439 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004440 unsigned int lnoff;
4441
Linus Torvalds1da177e2005-04-16 15:20:36 -07004442 /* BB fixme add lock for file (srch_info) struct here */
4443 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004444 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004445 else
Steve French4b18f2a2008-04-29 00:06:05 +00004446 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004447 response_data = (char *) &pSMBr->hdr.Protocol +
4448 le16_to_cpu(pSMBr->t2.ParameterOffset);
4449 parms = (T2_FNEXT_RSP_PARMS *)response_data;
4450 response_data = (char *)&pSMBr->hdr.Protocol +
4451 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00004452 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00004453 cifs_small_buf_release(
4454 psrch_inf->ntwrk_buf_start);
4455 else
4456 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004457 psrch_inf->srch_entries_start = response_data;
4458 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004459 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00004460 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004461 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004462 else
Steve French4b18f2a2008-04-29 00:06:05 +00004463 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00004464 psrch_inf->entries_in_buffer =
4465 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004466 psrch_inf->index_of_last_entry +=
4467 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004468 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004469 if (CIFSMaxBufSize < lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004470 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00004471 psrch_inf->last_entry = NULL;
4472 return rc;
4473 } else
4474 psrch_inf->last_entry =
4475 psrch_inf->srch_entries_start + lnoff;
4476
Joe Perchesb6b38f72010-04-21 03:50:45 +00004477/* cFYI(1, "fnxt2 entries in buf %d index_of_last %d",
4478 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004479
4480 /* BB fixme add unlock here */
4481 }
4482
4483 }
4484
4485 /* BB On error, should we leave previous search buf (and count and
4486 last entry fields) intact or free the previous one? */
4487
4488 /* Note: On -EAGAIN error only caller can retry on handle based calls
4489 since file handle passed in no longer valid */
4490FNext2_err_exit:
4491 if (rc != 0)
4492 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004493 return rc;
4494}
4495
4496int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004497CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004498 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004499{
4500 int rc = 0;
4501 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004502
Joe Perchesb6b38f72010-04-21 03:50:45 +00004503 cFYI(1, "In CIFSSMBFindClose");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004504 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
4505
4506 /* no sense returning error if session restarted
4507 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00004508 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004509 return 0;
4510 if (rc)
4511 return rc;
4512
Linus Torvalds1da177e2005-04-16 15:20:36 -07004513 pSMB->FileID = searchHandle;
4514 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04004515 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004516 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00004517 cERROR(1, "Send error in FindClose = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00004518
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004519 cifs_stats_inc(&tcon->stats.cifs_stats.num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004520
4521 /* Since session is dead, search handle closed on server already */
4522 if (rc == -EAGAIN)
4523 rc = 0;
4524
4525 return rc;
4526}
4527
Linus Torvalds1da177e2005-04-16 15:20:36 -07004528int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004529CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004530 const char *search_name, __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00004531 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004532{
4533 int rc = 0;
4534 TRANSACTION2_QPI_REQ *pSMB = NULL;
4535 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4536 int name_len, bytes_returned;
4537 __u16 params, byte_count;
4538
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004539 cFYI(1, "In GetSrvInodeNum for %s", search_name);
Steve French790fe572007-07-07 19:25:05 +00004540 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00004541 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004542
4543GetInodeNumberRetry:
4544 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004545 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004546 if (rc)
4547 return rc;
4548
Linus Torvalds1da177e2005-04-16 15:20:36 -07004549 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4550 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004551 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004552 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004553 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004554 name_len++; /* trailing null */
4555 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004556 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004557 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004558 name_len++; /* trailing null */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004559 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004560 }
4561
4562 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4563 pSMB->TotalDataCount = 0;
4564 pSMB->MaxParameterCount = cpu_to_le16(2);
4565 /* BB find exact max data count below from sess structure BB */
4566 pSMB->MaxDataCount = cpu_to_le16(4000);
4567 pSMB->MaxSetupCount = 0;
4568 pSMB->Reserved = 0;
4569 pSMB->Flags = 0;
4570 pSMB->Timeout = 0;
4571 pSMB->Reserved2 = 0;
4572 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004573 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004574 pSMB->DataCount = 0;
4575 pSMB->DataOffset = 0;
4576 pSMB->SetupCount = 1;
4577 pSMB->Reserved3 = 0;
4578 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4579 byte_count = params + 1 /* pad */ ;
4580 pSMB->TotalParameterCount = cpu_to_le16(params);
4581 pSMB->ParameterCount = pSMB->TotalParameterCount;
4582 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4583 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004584 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004585 pSMB->ByteCount = cpu_to_le16(byte_count);
4586
4587 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4588 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4589 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004590 cFYI(1, "error %d in QueryInternalInfo", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004591 } else {
4592 /* decode response */
4593 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004594 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04004595 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004596 /* If rc should we check for EOPNOSUPP and
4597 disable the srvino flag? or in caller? */
4598 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00004599 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004600 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4601 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00004602 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004603 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00004604 if (count < 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004605 cFYI(1, "Illegal size ret in QryIntrnlInf");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004606 rc = -EIO;
4607 goto GetInodeNumOut;
4608 }
4609 pfinfo = (struct file_internal_info *)
4610 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00004611 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004612 }
4613 }
4614GetInodeNumOut:
4615 cifs_buf_release(pSMB);
4616 if (rc == -EAGAIN)
4617 goto GetInodeNumberRetry;
4618 return rc;
4619}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004620
Igor Mammedovfec45852008-05-16 13:06:30 +04004621/* parses DFS refferal V3 structure
4622 * caller is responsible for freeing target_nodes
4623 * returns:
4624 * on success - 0
4625 * on failure - errno
4626 */
4627static int
Steve Frencha1fe78f2008-05-16 18:48:38 +00004628parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
Igor Mammedovfec45852008-05-16 13:06:30 +04004629 unsigned int *num_of_nodes,
4630 struct dfs_info3_param **target_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004631 const struct nls_table *nls_codepage, int remap,
4632 const char *searchName)
Igor Mammedovfec45852008-05-16 13:06:30 +04004633{
4634 int i, rc = 0;
4635 char *data_end;
4636 bool is_unicode;
4637 struct dfs_referral_level_3 *ref;
4638
Harvey Harrison5ca33c62008-07-23 17:45:58 -07004639 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4640 is_unicode = true;
4641 else
4642 is_unicode = false;
Igor Mammedovfec45852008-05-16 13:06:30 +04004643 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
4644
4645 if (*num_of_nodes < 1) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004646 cERROR(1, "num_referrals: must be at least > 0,"
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004647 "but we get num_referrals = %d", *num_of_nodes);
Igor Mammedovfec45852008-05-16 13:06:30 +04004648 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004649 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004650 }
4651
4652 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
Al Viro1d92cfd2008-06-02 10:59:02 +01004653 if (ref->VersionNumber != cpu_to_le16(3)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004654 cERROR(1, "Referrals of V%d version are not supported,"
4655 "should be V3", le16_to_cpu(ref->VersionNumber));
Igor Mammedovfec45852008-05-16 13:06:30 +04004656 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004657 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004658 }
4659
4660 /* get the upper boundary of the resp buffer */
4661 data_end = (char *)(&(pSMBr->PathConsumed)) +
4662 le16_to_cpu(pSMBr->t2.DataCount);
4663
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004664 cFYI(1, "num_referrals: %d dfs flags: 0x%x ...",
Igor Mammedovfec45852008-05-16 13:06:30 +04004665 *num_of_nodes,
Joe Perchesb6b38f72010-04-21 03:50:45 +00004666 le32_to_cpu(pSMBr->DFSFlags));
Igor Mammedovfec45852008-05-16 13:06:30 +04004667
4668 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
4669 *num_of_nodes, GFP_KERNEL);
4670 if (*target_nodes == NULL) {
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004671 cERROR(1, "Failed to allocate buffer for target_nodes");
Igor Mammedovfec45852008-05-16 13:06:30 +04004672 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004673 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004674 }
4675
Daniel Mack3ad2f3f2010-02-03 08:01:28 +08004676 /* collect necessary data from referrals */
Igor Mammedovfec45852008-05-16 13:06:30 +04004677 for (i = 0; i < *num_of_nodes; i++) {
4678 char *temp;
4679 int max_len;
4680 struct dfs_info3_param *node = (*target_nodes)+i;
4681
Steve French0e0d2cf2009-05-01 05:27:32 +00004682 node->flags = le32_to_cpu(pSMBr->DFSFlags);
Igor Mammedov2c556082008-10-23 13:58:42 +04004683 if (is_unicode) {
Jeff Layton331c3132008-12-17 06:31:53 -05004684 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4685 GFP_KERNEL);
Steve French2920ee22009-08-31 15:27:26 +00004686 if (tmp == NULL) {
4687 rc = -ENOMEM;
4688 goto parse_DFS_referrals_exit;
4689 }
Steve Frenchacbbb762012-01-18 22:32:33 -06004690 cifsConvertToUTF16((__le16 *) tmp, searchName,
4691 PATH_MAX, nls_codepage, remap);
4692 node->path_consumed = cifs_utf16_bytes(tmp,
Jeff Layton69f801f2009-04-30 06:46:32 -04004693 le16_to_cpu(pSMBr->PathConsumed),
Igor Mammedov2c556082008-10-23 13:58:42 +04004694 nls_codepage);
4695 kfree(tmp);
4696 } else
4697 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4698
Igor Mammedovfec45852008-05-16 13:06:30 +04004699 node->server_type = le16_to_cpu(ref->ServerType);
4700 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4701
4702 /* copy DfsPath */
4703 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4704 max_len = data_end - temp;
Steve Frenchacbbb762012-01-18 22:32:33 -06004705 node->path_name = cifs_strndup_from_utf16(temp, max_len,
4706 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004707 if (!node->path_name) {
4708 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004709 goto parse_DFS_referrals_exit;
Jeff Layton066ce682009-04-30 07:16:14 -04004710 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004711
4712 /* copy link target UNC */
4713 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4714 max_len = data_end - temp;
Steve Frenchacbbb762012-01-18 22:32:33 -06004715 node->node_name = cifs_strndup_from_utf16(temp, max_len,
4716 is_unicode, nls_codepage);
Stefan Metzmacherd8f27992012-05-04 00:19:28 +02004717 if (!node->node_name) {
Jeff Laytond8e2f532009-05-14 07:46:59 -04004718 rc = -ENOMEM;
Stefan Metzmacherd8f27992012-05-04 00:19:28 +02004719 goto parse_DFS_referrals_exit;
4720 }
4721
4722 ref++;
Igor Mammedovfec45852008-05-16 13:06:30 +04004723 }
4724
Steve Frencha1fe78f2008-05-16 18:48:38 +00004725parse_DFS_referrals_exit:
Igor Mammedovfec45852008-05-16 13:06:30 +04004726 if (rc) {
4727 free_dfs_info_array(*target_nodes, *num_of_nodes);
4728 *target_nodes = NULL;
4729 *num_of_nodes = 0;
4730 }
4731 return rc;
4732}
4733
Linus Torvalds1da177e2005-04-16 15:20:36 -07004734int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004735CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004736 const char *search_name, struct dfs_info3_param **target_nodes,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004737 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004738 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004739{
4740/* TRANS2_GET_DFS_REFERRAL */
4741 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4742 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004743 int rc = 0;
4744 int bytes_returned;
4745 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004746 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004747 *num_of_nodes = 0;
4748 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004749
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004750 cFYI(1, "In GetDFSRefer the path %s", search_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004751 if (ses == NULL)
4752 return -ENODEV;
4753getDFSRetry:
4754 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4755 (void **) &pSMBr);
4756 if (rc)
4757 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004758
4759 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004760 but should never be null here anyway */
Pavel Shilovsky88257362012-05-23 14:01:59 +04004761 pSMB->hdr.Mid = get_next_mid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004762 pSMB->hdr.Tid = ses->ipc_tid;
4763 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004764 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004765 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004766 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004767 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004768
4769 if (ses->capabilities & CAP_UNICODE) {
4770 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4771 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004772 cifsConvertToUTF16((__le16 *) pSMB->RequestFileName,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004773 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004774 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004775 name_len++; /* trailing null */
4776 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004777 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004778 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004779 name_len++; /* trailing null */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004780 strncpy(pSMB->RequestFileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004781 }
4782
Steve French790fe572007-07-07 19:25:05 +00004783 if (ses->server) {
Steve French96daf2b2011-05-27 04:34:02 +00004784 if (ses->server->sec_mode &
Steve French1a4e15a2006-10-12 21:33:51 +00004785 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4786 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4787 }
4788
Steve French50c2f752007-07-13 00:33:32 +00004789 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004790
Linus Torvalds1da177e2005-04-16 15:20:36 -07004791 params = 2 /* level */ + name_len /*includes null */ ;
4792 pSMB->TotalDataCount = 0;
4793 pSMB->DataCount = 0;
4794 pSMB->DataOffset = 0;
4795 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004796 /* BB find exact max SMB PDU from sess structure BB */
4797 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004798 pSMB->MaxSetupCount = 0;
4799 pSMB->Reserved = 0;
4800 pSMB->Flags = 0;
4801 pSMB->Timeout = 0;
4802 pSMB->Reserved2 = 0;
4803 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004804 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004805 pSMB->SetupCount = 1;
4806 pSMB->Reserved3 = 0;
4807 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4808 byte_count = params + 3 /* pad */ ;
4809 pSMB->ParameterCount = cpu_to_le16(params);
4810 pSMB->TotalParameterCount = pSMB->ParameterCount;
4811 pSMB->MaxReferralLevel = cpu_to_le16(3);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004812 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004813 pSMB->ByteCount = cpu_to_le16(byte_count);
4814
4815 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4816 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4817 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004818 cFYI(1, "Send error in GetDFSRefer = %d", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004819 goto GetDFSRefExit;
4820 }
4821 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004822
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004823 /* BB Also check if enough total bytes returned? */
Jeff Layton820a8032011-05-04 08:05:26 -04004824 if (rc || get_bcc(&pSMBr->hdr) < 17) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004825 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004826 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004827 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004828
Joe Perchesb6b38f72010-04-21 03:50:45 +00004829 cFYI(1, "Decoding GetDFSRefer response BCC: %d Offset %d",
Jeff Layton820a8032011-05-04 08:05:26 -04004830 get_bcc(&pSMBr->hdr),
Joe Perchesb6b38f72010-04-21 03:50:45 +00004831 le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04004832
4833 /* parse returned result into more usable form */
Steve Frencha1fe78f2008-05-16 18:48:38 +00004834 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004835 target_nodes, nls_codepage, remap,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004836 search_name);
Igor Mammedovfec45852008-05-16 13:06:30 +04004837
Linus Torvalds1da177e2005-04-16 15:20:36 -07004838GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004839 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004840
4841 if (rc == -EAGAIN)
4842 goto getDFSRetry;
4843
4844 return rc;
4845}
4846
Steve French20962432005-09-21 22:05:57 -07004847/* Query File System Info such as free space to old servers such as Win 9x */
4848int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004849SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4850 struct kstatfs *FSData)
Steve French20962432005-09-21 22:05:57 -07004851{
4852/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4853 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4854 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4855 FILE_SYSTEM_ALLOC_INFO *response_data;
4856 int rc = 0;
4857 int bytes_returned = 0;
4858 __u16 params, byte_count;
4859
Joe Perchesb6b38f72010-04-21 03:50:45 +00004860 cFYI(1, "OldQFSInfo");
Steve French20962432005-09-21 22:05:57 -07004861oldQFSInfoRetry:
4862 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4863 (void **) &pSMBr);
4864 if (rc)
4865 return rc;
Steve French20962432005-09-21 22:05:57 -07004866
4867 params = 2; /* level */
4868 pSMB->TotalDataCount = 0;
4869 pSMB->MaxParameterCount = cpu_to_le16(2);
4870 pSMB->MaxDataCount = cpu_to_le16(1000);
4871 pSMB->MaxSetupCount = 0;
4872 pSMB->Reserved = 0;
4873 pSMB->Flags = 0;
4874 pSMB->Timeout = 0;
4875 pSMB->Reserved2 = 0;
4876 byte_count = params + 1 /* pad */ ;
4877 pSMB->TotalParameterCount = cpu_to_le16(params);
4878 pSMB->ParameterCount = pSMB->TotalParameterCount;
4879 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4880 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4881 pSMB->DataCount = 0;
4882 pSMB->DataOffset = 0;
4883 pSMB->SetupCount = 1;
4884 pSMB->Reserved3 = 0;
4885 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4886 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004887 inc_rfc1001_len(pSMB, byte_count);
Steve French20962432005-09-21 22:05:57 -07004888 pSMB->ByteCount = cpu_to_le16(byte_count);
4889
4890 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4891 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4892 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004893 cFYI(1, "Send error in QFSInfo = %d", rc);
Steve French20962432005-09-21 22:05:57 -07004894 } else { /* decode response */
4895 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4896
Jeff Layton820a8032011-05-04 08:05:26 -04004897 if (rc || get_bcc(&pSMBr->hdr) < 18)
Steve French20962432005-09-21 22:05:57 -07004898 rc = -EIO; /* bad smb */
4899 else {
4900 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004901 cFYI(1, "qfsinf resp BCC: %d Offset %d",
Jeff Layton820a8032011-05-04 08:05:26 -04004902 get_bcc(&pSMBr->hdr), data_offset);
Steve French20962432005-09-21 22:05:57 -07004903
Steve French50c2f752007-07-13 00:33:32 +00004904 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004905 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4906 FSData->f_bsize =
4907 le16_to_cpu(response_data->BytesPerSector) *
4908 le32_to_cpu(response_data->
4909 SectorsPerAllocationUnit);
4910 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004911 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004912 FSData->f_bfree = FSData->f_bavail =
4913 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004914 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
4915 (unsigned long long)FSData->f_blocks,
4916 (unsigned long long)FSData->f_bfree,
4917 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07004918 }
4919 }
4920 cifs_buf_release(pSMB);
4921
4922 if (rc == -EAGAIN)
4923 goto oldQFSInfoRetry;
4924
4925 return rc;
4926}
4927
Linus Torvalds1da177e2005-04-16 15:20:36 -07004928int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004929CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4930 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004931{
4932/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4933 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4934 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4935 FILE_SYSTEM_INFO *response_data;
4936 int rc = 0;
4937 int bytes_returned = 0;
4938 __u16 params, byte_count;
4939
Joe Perchesb6b38f72010-04-21 03:50:45 +00004940 cFYI(1, "In QFSInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004941QFSInfoRetry:
4942 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4943 (void **) &pSMBr);
4944 if (rc)
4945 return rc;
4946
4947 params = 2; /* level */
4948 pSMB->TotalDataCount = 0;
4949 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004950 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004951 pSMB->MaxSetupCount = 0;
4952 pSMB->Reserved = 0;
4953 pSMB->Flags = 0;
4954 pSMB->Timeout = 0;
4955 pSMB->Reserved2 = 0;
4956 byte_count = params + 1 /* pad */ ;
4957 pSMB->TotalParameterCount = cpu_to_le16(params);
4958 pSMB->ParameterCount = pSMB->TotalParameterCount;
4959 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004960 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004961 pSMB->DataCount = 0;
4962 pSMB->DataOffset = 0;
4963 pSMB->SetupCount = 1;
4964 pSMB->Reserved3 = 0;
4965 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4966 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004967 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004968 pSMB->ByteCount = cpu_to_le16(byte_count);
4969
4970 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4971 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4972 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004973 cFYI(1, "Send error in QFSInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004974 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00004975 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004976
Jeff Layton820a8032011-05-04 08:05:26 -04004977 if (rc || get_bcc(&pSMBr->hdr) < 24)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004978 rc = -EIO; /* bad smb */
4979 else {
4980 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004981
4982 response_data =
4983 (FILE_SYSTEM_INFO
4984 *) (((char *) &pSMBr->hdr.Protocol) +
4985 data_offset);
4986 FSData->f_bsize =
4987 le32_to_cpu(response_data->BytesPerSector) *
4988 le32_to_cpu(response_data->
4989 SectorsPerAllocationUnit);
4990 FSData->f_blocks =
4991 le64_to_cpu(response_data->TotalAllocationUnits);
4992 FSData->f_bfree = FSData->f_bavail =
4993 le64_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004994 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
4995 (unsigned long long)FSData->f_blocks,
4996 (unsigned long long)FSData->f_bfree,
4997 FSData->f_bsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004998 }
4999 }
5000 cifs_buf_release(pSMB);
5001
5002 if (rc == -EAGAIN)
5003 goto QFSInfoRetry;
5004
5005 return rc;
5006}
5007
5008int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005009CIFSSMBQFSAttributeInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005010{
5011/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
5012 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5013 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5014 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
5015 int rc = 0;
5016 int bytes_returned = 0;
5017 __u16 params, byte_count;
5018
Joe Perchesb6b38f72010-04-21 03:50:45 +00005019 cFYI(1, "In QFSAttributeInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005020QFSAttributeRetry:
5021 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5022 (void **) &pSMBr);
5023 if (rc)
5024 return rc;
5025
5026 params = 2; /* level */
5027 pSMB->TotalDataCount = 0;
5028 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005029 /* BB find exact max SMB PDU from sess structure BB */
5030 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005031 pSMB->MaxSetupCount = 0;
5032 pSMB->Reserved = 0;
5033 pSMB->Flags = 0;
5034 pSMB->Timeout = 0;
5035 pSMB->Reserved2 = 0;
5036 byte_count = params + 1 /* pad */ ;
5037 pSMB->TotalParameterCount = cpu_to_le16(params);
5038 pSMB->ParameterCount = pSMB->TotalParameterCount;
5039 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005040 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005041 pSMB->DataCount = 0;
5042 pSMB->DataOffset = 0;
5043 pSMB->SetupCount = 1;
5044 pSMB->Reserved3 = 0;
5045 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5046 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005047 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005048 pSMB->ByteCount = cpu_to_le16(byte_count);
5049
5050 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5051 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5052 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005053 cERROR(1, "Send error in QFSAttributeInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005054 } else { /* decode response */
5055 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5056
Jeff Layton820a8032011-05-04 08:05:26 -04005057 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Steve French50c2f752007-07-13 00:33:32 +00005058 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005059 rc = -EIO; /* bad smb */
5060 } else {
5061 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5062 response_data =
5063 (FILE_SYSTEM_ATTRIBUTE_INFO
5064 *) (((char *) &pSMBr->hdr.Protocol) +
5065 data_offset);
5066 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005067 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005068 }
5069 }
5070 cifs_buf_release(pSMB);
5071
5072 if (rc == -EAGAIN)
5073 goto QFSAttributeRetry;
5074
5075 return rc;
5076}
5077
5078int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005079CIFSSMBQFSDeviceInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005080{
5081/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
5082 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5083 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5084 FILE_SYSTEM_DEVICE_INFO *response_data;
5085 int rc = 0;
5086 int bytes_returned = 0;
5087 __u16 params, byte_count;
5088
Joe Perchesb6b38f72010-04-21 03:50:45 +00005089 cFYI(1, "In QFSDeviceInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005090QFSDeviceRetry:
5091 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5092 (void **) &pSMBr);
5093 if (rc)
5094 return rc;
5095
5096 params = 2; /* level */
5097 pSMB->TotalDataCount = 0;
5098 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005099 /* BB find exact max SMB PDU from sess structure BB */
5100 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005101 pSMB->MaxSetupCount = 0;
5102 pSMB->Reserved = 0;
5103 pSMB->Flags = 0;
5104 pSMB->Timeout = 0;
5105 pSMB->Reserved2 = 0;
5106 byte_count = params + 1 /* pad */ ;
5107 pSMB->TotalParameterCount = cpu_to_le16(params);
5108 pSMB->ParameterCount = pSMB->TotalParameterCount;
5109 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005110 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005111
5112 pSMB->DataCount = 0;
5113 pSMB->DataOffset = 0;
5114 pSMB->SetupCount = 1;
5115 pSMB->Reserved3 = 0;
5116 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5117 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005118 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005119 pSMB->ByteCount = cpu_to_le16(byte_count);
5120
5121 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5122 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5123 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005124 cFYI(1, "Send error in QFSDeviceInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005125 } else { /* decode response */
5126 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5127
Jeff Layton820a8032011-05-04 08:05:26 -04005128 if (rc || get_bcc(&pSMBr->hdr) <
5129 sizeof(FILE_SYSTEM_DEVICE_INFO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005130 rc = -EIO; /* bad smb */
5131 else {
5132 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5133 response_data =
Steve French737b7582005-04-28 22:41:06 -07005134 (FILE_SYSTEM_DEVICE_INFO *)
5135 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07005136 data_offset);
5137 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005138 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005139 }
5140 }
5141 cifs_buf_release(pSMB);
5142
5143 if (rc == -EAGAIN)
5144 goto QFSDeviceRetry;
5145
5146 return rc;
5147}
5148
5149int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005150CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005151{
5152/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
5153 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5154 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5155 FILE_SYSTEM_UNIX_INFO *response_data;
5156 int rc = 0;
5157 int bytes_returned = 0;
5158 __u16 params, byte_count;
5159
Joe Perchesb6b38f72010-04-21 03:50:45 +00005160 cFYI(1, "In QFSUnixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005161QFSUnixRetry:
Jeff Laytonf5695992010-09-29 15:27:08 -04005162 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5163 (void **) &pSMB, (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005164 if (rc)
5165 return rc;
5166
5167 params = 2; /* level */
5168 pSMB->TotalDataCount = 0;
5169 pSMB->DataCount = 0;
5170 pSMB->DataOffset = 0;
5171 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005172 /* BB find exact max SMB PDU from sess structure BB */
5173 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005174 pSMB->MaxSetupCount = 0;
5175 pSMB->Reserved = 0;
5176 pSMB->Flags = 0;
5177 pSMB->Timeout = 0;
5178 pSMB->Reserved2 = 0;
5179 byte_count = params + 1 /* pad */ ;
5180 pSMB->ParameterCount = cpu_to_le16(params);
5181 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005182 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5183 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005184 pSMB->SetupCount = 1;
5185 pSMB->Reserved3 = 0;
5186 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5187 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005188 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005189 pSMB->ByteCount = cpu_to_le16(byte_count);
5190
5191 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5192 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5193 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005194 cERROR(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005195 } else { /* decode response */
5196 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5197
Jeff Layton820a8032011-05-04 08:05:26 -04005198 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005199 rc = -EIO; /* bad smb */
5200 } else {
5201 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5202 response_data =
5203 (FILE_SYSTEM_UNIX_INFO
5204 *) (((char *) &pSMBr->hdr.Protocol) +
5205 data_offset);
5206 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005207 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005208 }
5209 }
5210 cifs_buf_release(pSMB);
5211
5212 if (rc == -EAGAIN)
5213 goto QFSUnixRetry;
5214
5215
5216 return rc;
5217}
5218
Jeremy Allisonac670552005-06-22 17:26:35 -07005219int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005220CIFSSMBSetFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07005221{
5222/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
5223 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
5224 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
5225 int rc = 0;
5226 int bytes_returned = 0;
5227 __u16 params, param_offset, offset, byte_count;
5228
Joe Perchesb6b38f72010-04-21 03:50:45 +00005229 cFYI(1, "In SETFSUnixInfo");
Jeremy Allisonac670552005-06-22 17:26:35 -07005230SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00005231 /* BB switch to small buf init to save memory */
Jeff Laytonf5695992010-09-29 15:27:08 -04005232 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5233 (void **) &pSMB, (void **) &pSMBr);
Jeremy Allisonac670552005-06-22 17:26:35 -07005234 if (rc)
5235 return rc;
5236
5237 params = 4; /* 2 bytes zero followed by info level. */
5238 pSMB->MaxSetupCount = 0;
5239 pSMB->Reserved = 0;
5240 pSMB->Flags = 0;
5241 pSMB->Timeout = 0;
5242 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00005243 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
5244 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07005245 offset = param_offset + params;
5246
5247 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00005248 /* BB find exact max SMB PDU from sess structure BB */
5249 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07005250 pSMB->SetupCount = 1;
5251 pSMB->Reserved3 = 0;
5252 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
5253 byte_count = 1 /* pad */ + params + 12;
5254
5255 pSMB->DataCount = cpu_to_le16(12);
5256 pSMB->ParameterCount = cpu_to_le16(params);
5257 pSMB->TotalDataCount = pSMB->DataCount;
5258 pSMB->TotalParameterCount = pSMB->ParameterCount;
5259 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5260 pSMB->DataOffset = cpu_to_le16(offset);
5261
5262 /* Params. */
5263 pSMB->FileNum = 0;
5264 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
5265
5266 /* Data. */
5267 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
5268 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
5269 pSMB->ClientUnixCap = cpu_to_le64(cap);
5270
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005271 inc_rfc1001_len(pSMB, byte_count);
Jeremy Allisonac670552005-06-22 17:26:35 -07005272 pSMB->ByteCount = cpu_to_le16(byte_count);
5273
5274 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5275 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5276 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005277 cERROR(1, "Send error in SETFSUnixInfo = %d", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07005278 } else { /* decode response */
5279 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00005280 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07005281 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07005282 }
5283 cifs_buf_release(pSMB);
5284
5285 if (rc == -EAGAIN)
5286 goto SETFSUnixRetry;
5287
5288 return rc;
5289}
5290
5291
Linus Torvalds1da177e2005-04-16 15:20:36 -07005292
5293int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005294CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon,
Steve French737b7582005-04-28 22:41:06 -07005295 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005296{
5297/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
5298 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5299 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5300 FILE_SYSTEM_POSIX_INFO *response_data;
5301 int rc = 0;
5302 int bytes_returned = 0;
5303 __u16 params, byte_count;
5304
Joe Perchesb6b38f72010-04-21 03:50:45 +00005305 cFYI(1, "In QFSPosixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005306QFSPosixRetry:
5307 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5308 (void **) &pSMBr);
5309 if (rc)
5310 return rc;
5311
5312 params = 2; /* level */
5313 pSMB->TotalDataCount = 0;
5314 pSMB->DataCount = 0;
5315 pSMB->DataOffset = 0;
5316 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005317 /* BB find exact max SMB PDU from sess structure BB */
5318 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005319 pSMB->MaxSetupCount = 0;
5320 pSMB->Reserved = 0;
5321 pSMB->Flags = 0;
5322 pSMB->Timeout = 0;
5323 pSMB->Reserved2 = 0;
5324 byte_count = params + 1 /* pad */ ;
5325 pSMB->ParameterCount = cpu_to_le16(params);
5326 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005327 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5328 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005329 pSMB->SetupCount = 1;
5330 pSMB->Reserved3 = 0;
5331 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5332 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005333 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005334 pSMB->ByteCount = cpu_to_le16(byte_count);
5335
5336 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5337 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5338 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005339 cFYI(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005340 } else { /* decode response */
5341 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5342
Jeff Layton820a8032011-05-04 08:05:26 -04005343 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005344 rc = -EIO; /* bad smb */
5345 } else {
5346 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5347 response_data =
5348 (FILE_SYSTEM_POSIX_INFO
5349 *) (((char *) &pSMBr->hdr.Protocol) +
5350 data_offset);
5351 FSData->f_bsize =
5352 le32_to_cpu(response_data->BlockSize);
5353 FSData->f_blocks =
5354 le64_to_cpu(response_data->TotalBlocks);
5355 FSData->f_bfree =
5356 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00005357 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005358 FSData->f_bavail = FSData->f_bfree;
5359 } else {
5360 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00005361 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005362 }
Steve French790fe572007-07-07 19:25:05 +00005363 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005364 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00005365 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00005366 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005367 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00005368 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005369 }
5370 }
5371 cifs_buf_release(pSMB);
5372
5373 if (rc == -EAGAIN)
5374 goto QFSPosixRetry;
5375
5376 return rc;
5377}
5378
5379
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005380/*
5381 * We can not use write of zero bytes trick to set file size due to need for
5382 * large file support. Also note that this SetPathInfo is preferred to
5383 * SetFileInfo based method in next routine which is only needed to work around
5384 * a sharing violation bugin Samba which this routine can run into.
5385 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005386int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005387CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005388 const char *file_name, __u64 size, struct cifs_sb_info *cifs_sb,
5389 bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005390{
5391 struct smb_com_transaction2_spi_req *pSMB = NULL;
5392 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5393 struct file_end_of_file_info *parm_data;
5394 int name_len;
5395 int rc = 0;
5396 int bytes_returned = 0;
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005397 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
5398
Linus Torvalds1da177e2005-04-16 15:20:36 -07005399 __u16 params, byte_count, data_count, param_offset, offset;
5400
Joe Perchesb6b38f72010-04-21 03:50:45 +00005401 cFYI(1, "In SetEOF");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005402SetEOFRetry:
5403 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5404 (void **) &pSMBr);
5405 if (rc)
5406 return rc;
5407
5408 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5409 name_len =
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005410 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
5411 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005412 name_len++; /* trailing null */
5413 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005414 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005415 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005416 name_len++; /* trailing null */
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005417 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005418 }
5419 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005420 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005421 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07005422 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005423 pSMB->MaxSetupCount = 0;
5424 pSMB->Reserved = 0;
5425 pSMB->Flags = 0;
5426 pSMB->Timeout = 0;
5427 pSMB->Reserved2 = 0;
5428 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005429 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005430 offset = param_offset + params;
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005431 if (set_allocation) {
Steve French50c2f752007-07-13 00:33:32 +00005432 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5433 pSMB->InformationLevel =
5434 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5435 else
5436 pSMB->InformationLevel =
5437 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5438 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005439 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5440 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005441 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005442 else
5443 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005444 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005445 }
5446
5447 parm_data =
5448 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
5449 offset);
5450 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5451 pSMB->DataOffset = cpu_to_le16(offset);
5452 pSMB->SetupCount = 1;
5453 pSMB->Reserved3 = 0;
5454 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5455 byte_count = 3 /* pad */ + params + data_count;
5456 pSMB->DataCount = cpu_to_le16(data_count);
5457 pSMB->TotalDataCount = pSMB->DataCount;
5458 pSMB->ParameterCount = cpu_to_le16(params);
5459 pSMB->TotalParameterCount = pSMB->ParameterCount;
5460 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005461 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005462 parm_data->FileSize = cpu_to_le64(size);
5463 pSMB->ByteCount = cpu_to_le16(byte_count);
5464 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5465 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005466 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005467 cFYI(1, "SetPathInfo (file size) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005468
5469 cifs_buf_release(pSMB);
5470
5471 if (rc == -EAGAIN)
5472 goto SetEOFRetry;
5473
5474 return rc;
5475}
5476
5477int
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005478CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
5479 struct cifsFileInfo *cfile, __u64 size, bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005480{
5481 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005482 struct file_end_of_file_info *parm_data;
5483 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005484 __u16 params, param_offset, offset, byte_count, count;
5485
Joe Perchesb6b38f72010-04-21 03:50:45 +00005486 cFYI(1, "SetFileSize (via SetFileInfo) %lld",
5487 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07005488 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5489
Linus Torvalds1da177e2005-04-16 15:20:36 -07005490 if (rc)
5491 return rc;
5492
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005493 pSMB->hdr.Pid = cpu_to_le16((__u16)cfile->pid);
5494 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(cfile->pid >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005495
Linus Torvalds1da177e2005-04-16 15:20:36 -07005496 params = 6;
5497 pSMB->MaxSetupCount = 0;
5498 pSMB->Reserved = 0;
5499 pSMB->Flags = 0;
5500 pSMB->Timeout = 0;
5501 pSMB->Reserved2 = 0;
5502 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5503 offset = param_offset + params;
5504
Linus Torvalds1da177e2005-04-16 15:20:36 -07005505 count = sizeof(struct file_end_of_file_info);
5506 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005507 /* BB find exact max SMB PDU from sess structure BB */
5508 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005509 pSMB->SetupCount = 1;
5510 pSMB->Reserved3 = 0;
5511 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5512 byte_count = 3 /* pad */ + params + count;
5513 pSMB->DataCount = cpu_to_le16(count);
5514 pSMB->ParameterCount = cpu_to_le16(params);
5515 pSMB->TotalDataCount = pSMB->DataCount;
5516 pSMB->TotalParameterCount = pSMB->ParameterCount;
5517 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5518 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00005519 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
5520 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005521 pSMB->DataOffset = cpu_to_le16(offset);
5522 parm_data->FileSize = cpu_to_le64(size);
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005523 pSMB->Fid = cfile->fid.netfid;
5524 if (set_allocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005525 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5526 pSMB->InformationLevel =
5527 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5528 else
5529 pSMB->InformationLevel =
5530 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00005531 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005532 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5533 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005534 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005535 else
5536 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005537 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005538 }
5539 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005540 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005541 pSMB->ByteCount = cpu_to_le16(byte_count);
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005542 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005543 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005544 cFYI(1, "Send error in SetFileInfo (SetFileSize) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005545 }
5546
Steve French50c2f752007-07-13 00:33:32 +00005547 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005548 since file handle passed in no longer valid */
5549
5550 return rc;
5551}
5552
Steve French50c2f752007-07-13 00:33:32 +00005553/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07005554 an open handle, rather than by pathname - this is awkward due to
5555 potential access conflicts on the open, but it is unavoidable for these
5556 old servers since the only other choice is to go from 100 nanosecond DCE
5557 time and resort to the original setpathinfo level which takes the ancient
5558 DOS time format with 2 second granularity */
5559int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005560CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005561 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005562{
5563 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005564 char *data_offset;
5565 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005566 __u16 params, param_offset, offset, byte_count, count;
5567
Joe Perchesb6b38f72010-04-21 03:50:45 +00005568 cFYI(1, "Set Times (via SetFileInfo)");
Steve Frenchcd634992005-04-28 22:41:10 -07005569 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5570
Linus Torvalds1da177e2005-04-16 15:20:36 -07005571 if (rc)
5572 return rc;
5573
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005574 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5575 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005576
Linus Torvalds1da177e2005-04-16 15:20:36 -07005577 params = 6;
5578 pSMB->MaxSetupCount = 0;
5579 pSMB->Reserved = 0;
5580 pSMB->Flags = 0;
5581 pSMB->Timeout = 0;
5582 pSMB->Reserved2 = 0;
5583 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5584 offset = param_offset + params;
5585
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005586 data_offset = (char *)pSMB +
5587 offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005588
Steve French26f57362007-08-30 22:09:15 +00005589 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005590 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005591 /* BB find max SMB PDU from sess */
5592 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005593 pSMB->SetupCount = 1;
5594 pSMB->Reserved3 = 0;
5595 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5596 byte_count = 3 /* pad */ + params + count;
5597 pSMB->DataCount = cpu_to_le16(count);
5598 pSMB->ParameterCount = cpu_to_le16(params);
5599 pSMB->TotalDataCount = pSMB->DataCount;
5600 pSMB->TotalParameterCount = pSMB->ParameterCount;
5601 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5602 pSMB->DataOffset = cpu_to_le16(offset);
5603 pSMB->Fid = fid;
5604 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5605 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5606 else
5607 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5608 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005609 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005610 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005611 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005612 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005613 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005614 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005615
Steve French50c2f752007-07-13 00:33:32 +00005616 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005617 since file handle passed in no longer valid */
5618
5619 return rc;
5620}
5621
Jeff Layton6d22f092008-09-23 11:48:35 -04005622int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005623CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6d22f092008-09-23 11:48:35 -04005624 bool delete_file, __u16 fid, __u32 pid_of_opener)
5625{
5626 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5627 char *data_offset;
5628 int rc = 0;
5629 __u16 params, param_offset, offset, byte_count, count;
5630
Joe Perchesb6b38f72010-04-21 03:50:45 +00005631 cFYI(1, "Set File Disposition (via SetFileInfo)");
Jeff Layton6d22f092008-09-23 11:48:35 -04005632 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5633
5634 if (rc)
5635 return rc;
5636
5637 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5638 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5639
5640 params = 6;
5641 pSMB->MaxSetupCount = 0;
5642 pSMB->Reserved = 0;
5643 pSMB->Flags = 0;
5644 pSMB->Timeout = 0;
5645 pSMB->Reserved2 = 0;
5646 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5647 offset = param_offset + params;
5648
5649 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5650
5651 count = 1;
5652 pSMB->MaxParameterCount = cpu_to_le16(2);
5653 /* BB find max SMB PDU from sess */
5654 pSMB->MaxDataCount = cpu_to_le16(1000);
5655 pSMB->SetupCount = 1;
5656 pSMB->Reserved3 = 0;
5657 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5658 byte_count = 3 /* pad */ + params + count;
5659 pSMB->DataCount = cpu_to_le16(count);
5660 pSMB->ParameterCount = cpu_to_le16(params);
5661 pSMB->TotalDataCount = pSMB->DataCount;
5662 pSMB->TotalParameterCount = pSMB->ParameterCount;
5663 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5664 pSMB->DataOffset = cpu_to_le16(offset);
5665 pSMB->Fid = fid;
5666 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5667 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005668 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton6d22f092008-09-23 11:48:35 -04005669 pSMB->ByteCount = cpu_to_le16(byte_count);
5670 *data_offset = delete_file ? 1 : 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005671 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Jeff Layton6d22f092008-09-23 11:48:35 -04005672 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005673 cFYI(1, "Send error in SetFileDisposition = %d", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005674
5675 return rc;
5676}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005677
5678int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005679CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6fc000e2008-08-02 07:26:12 -04005680 const char *fileName, const FILE_BASIC_INFO *data,
5681 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005682{
5683 TRANSACTION2_SPI_REQ *pSMB = NULL;
5684 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5685 int name_len;
5686 int rc = 0;
5687 int bytes_returned = 0;
5688 char *data_offset;
5689 __u16 params, param_offset, offset, byte_count, count;
5690
Joe Perchesb6b38f72010-04-21 03:50:45 +00005691 cFYI(1, "In SetTimes");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005692
5693SetTimesRetry:
5694 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5695 (void **) &pSMBr);
5696 if (rc)
5697 return rc;
5698
5699 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5700 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005701 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5702 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005703 name_len++; /* trailing null */
5704 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005705 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005706 name_len = strnlen(fileName, PATH_MAX);
5707 name_len++; /* trailing null */
5708 strncpy(pSMB->FileName, fileName, name_len);
5709 }
5710
5711 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005712 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005713 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005714 /* BB find max SMB PDU from sess structure BB */
5715 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005716 pSMB->MaxSetupCount = 0;
5717 pSMB->Reserved = 0;
5718 pSMB->Flags = 0;
5719 pSMB->Timeout = 0;
5720 pSMB->Reserved2 = 0;
5721 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005722 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005723 offset = param_offset + params;
5724 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5725 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5726 pSMB->DataOffset = cpu_to_le16(offset);
5727 pSMB->SetupCount = 1;
5728 pSMB->Reserved3 = 0;
5729 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5730 byte_count = 3 /* pad */ + params + count;
5731
5732 pSMB->DataCount = cpu_to_le16(count);
5733 pSMB->ParameterCount = cpu_to_le16(params);
5734 pSMB->TotalDataCount = pSMB->DataCount;
5735 pSMB->TotalParameterCount = pSMB->ParameterCount;
5736 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5737 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5738 else
5739 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5740 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005741 inc_rfc1001_len(pSMB, byte_count);
Steve French26f57362007-08-30 22:09:15 +00005742 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005743 pSMB->ByteCount = cpu_to_le16(byte_count);
5744 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5745 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005746 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005747 cFYI(1, "SetPathInfo (times) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005748
5749 cifs_buf_release(pSMB);
5750
5751 if (rc == -EAGAIN)
5752 goto SetTimesRetry;
5753
5754 return rc;
5755}
5756
5757/* Can not be used to set time stamps yet (due to old DOS time format) */
5758/* Can be used to set attributes */
5759#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5760 handling it anyway and NT4 was what we thought it would be needed for
5761 Do not delete it until we prove whether needed for Win9x though */
5762int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005763CIFSSMBSetAttrLegacy(unsigned int xid, struct cifs_tcon *tcon, char *fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005764 __u16 dos_attrs, const struct nls_table *nls_codepage)
5765{
5766 SETATTR_REQ *pSMB = NULL;
5767 SETATTR_RSP *pSMBr = NULL;
5768 int rc = 0;
5769 int bytes_returned;
5770 int name_len;
5771
Joe Perchesb6b38f72010-04-21 03:50:45 +00005772 cFYI(1, "In SetAttrLegacy");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005773
5774SetAttrLgcyRetry:
5775 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5776 (void **) &pSMBr);
5777 if (rc)
5778 return rc;
5779
5780 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5781 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005782 ConvertToUTF16((__le16 *) pSMB->fileName, fileName,
5783 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005784 name_len++; /* trailing null */
5785 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005786 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005787 name_len = strnlen(fileName, PATH_MAX);
5788 name_len++; /* trailing null */
5789 strncpy(pSMB->fileName, fileName, name_len);
5790 }
5791 pSMB->attr = cpu_to_le16(dos_attrs);
5792 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005793 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005794 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5795 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5796 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005797 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005798 cFYI(1, "Error in LegacySetAttr = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005799
5800 cifs_buf_release(pSMB);
5801
5802 if (rc == -EAGAIN)
5803 goto SetAttrLgcyRetry;
5804
5805 return rc;
5806}
5807#endif /* temporarily unneeded SetAttr legacy function */
5808
Jeff Layton654cf142009-07-09 20:02:49 -04005809static void
5810cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5811 const struct cifs_unix_set_info_args *args)
5812{
5813 u64 mode = args->mode;
5814
5815 /*
5816 * Samba server ignores set of file size to zero due to bugs in some
5817 * older clients, but we should be precise - we use SetFileSize to
5818 * set file size and do not want to truncate file size to zero
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005819 * accidentally as happened on one Samba server beta by putting
Jeff Layton654cf142009-07-09 20:02:49 -04005820 * zero instead of -1 here
5821 */
5822 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5823 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5824 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5825 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5826 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5827 data_offset->Uid = cpu_to_le64(args->uid);
5828 data_offset->Gid = cpu_to_le64(args->gid);
5829 /* better to leave device as zero when it is */
5830 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5831 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5832 data_offset->Permissions = cpu_to_le64(mode);
5833
5834 if (S_ISREG(mode))
5835 data_offset->Type = cpu_to_le32(UNIX_FILE);
5836 else if (S_ISDIR(mode))
5837 data_offset->Type = cpu_to_le32(UNIX_DIR);
5838 else if (S_ISLNK(mode))
5839 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5840 else if (S_ISCHR(mode))
5841 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5842 else if (S_ISBLK(mode))
5843 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5844 else if (S_ISFIFO(mode))
5845 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5846 else if (S_ISSOCK(mode))
5847 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5848}
5849
Linus Torvalds1da177e2005-04-16 15:20:36 -07005850int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005851CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005852 const struct cifs_unix_set_info_args *args,
5853 u16 fid, u32 pid_of_opener)
5854{
5855 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005856 char *data_offset;
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005857 int rc = 0;
5858 u16 params, param_offset, offset, byte_count, count;
5859
Joe Perchesb6b38f72010-04-21 03:50:45 +00005860 cFYI(1, "Set Unix Info (via SetFileInfo)");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005861 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5862
5863 if (rc)
5864 return rc;
5865
5866 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5867 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5868
5869 params = 6;
5870 pSMB->MaxSetupCount = 0;
5871 pSMB->Reserved = 0;
5872 pSMB->Flags = 0;
5873 pSMB->Timeout = 0;
5874 pSMB->Reserved2 = 0;
5875 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5876 offset = param_offset + params;
5877
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005878 data_offset = (char *)pSMB +
5879 offsetof(struct smb_hdr, Protocol) + offset;
5880
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005881 count = sizeof(FILE_UNIX_BASIC_INFO);
5882
5883 pSMB->MaxParameterCount = cpu_to_le16(2);
5884 /* BB find max SMB PDU from sess */
5885 pSMB->MaxDataCount = cpu_to_le16(1000);
5886 pSMB->SetupCount = 1;
5887 pSMB->Reserved3 = 0;
5888 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5889 byte_count = 3 /* pad */ + params + count;
5890 pSMB->DataCount = cpu_to_le16(count);
5891 pSMB->ParameterCount = cpu_to_le16(params);
5892 pSMB->TotalDataCount = pSMB->DataCount;
5893 pSMB->TotalParameterCount = pSMB->ParameterCount;
5894 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5895 pSMB->DataOffset = cpu_to_le16(offset);
5896 pSMB->Fid = fid;
5897 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5898 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005899 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005900 pSMB->ByteCount = cpu_to_le16(byte_count);
5901
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005902 cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005903
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005904 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005905 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005906 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005907
5908 /* Note: On -EAGAIN error only caller can retry on handle based calls
5909 since file handle passed in no longer valid */
5910
5911 return rc;
5912}
5913
5914int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005915CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005916 const char *file_name,
Jeff Layton01ea95e2009-07-09 20:02:49 -04005917 const struct cifs_unix_set_info_args *args,
5918 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005919{
5920 TRANSACTION2_SPI_REQ *pSMB = NULL;
5921 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5922 int name_len;
5923 int rc = 0;
5924 int bytes_returned = 0;
5925 FILE_UNIX_BASIC_INFO *data_offset;
5926 __u16 params, param_offset, offset, count, byte_count;
5927
Joe Perchesb6b38f72010-04-21 03:50:45 +00005928 cFYI(1, "In SetUID/GID/Mode");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005929setPermsRetry:
5930 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5931 (void **) &pSMBr);
5932 if (rc)
5933 return rc;
5934
5935 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5936 name_len =
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005937 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06005938 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005939 name_len++; /* trailing null */
5940 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005941 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005942 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005943 name_len++; /* trailing null */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005944 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005945 }
5946
5947 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005948 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005949 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005950 /* BB find max SMB PDU from sess structure BB */
5951 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005952 pSMB->MaxSetupCount = 0;
5953 pSMB->Reserved = 0;
5954 pSMB->Flags = 0;
5955 pSMB->Timeout = 0;
5956 pSMB->Reserved2 = 0;
5957 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005958 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005959 offset = param_offset + params;
5960 data_offset =
5961 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5962 offset);
5963 memset(data_offset, 0, count);
5964 pSMB->DataOffset = cpu_to_le16(offset);
5965 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5966 pSMB->SetupCount = 1;
5967 pSMB->Reserved3 = 0;
5968 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5969 byte_count = 3 /* pad */ + params + count;
5970 pSMB->ParameterCount = cpu_to_le16(params);
5971 pSMB->DataCount = cpu_to_le16(count);
5972 pSMB->TotalParameterCount = pSMB->ParameterCount;
5973 pSMB->TotalDataCount = pSMB->DataCount;
5974 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5975 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005976 inc_rfc1001_len(pSMB, byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005977
Jeff Layton654cf142009-07-09 20:02:49 -04005978 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005979
5980 pSMB->ByteCount = cpu_to_le16(byte_count);
5981 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5982 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005983 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005984 cFYI(1, "SetPathInfo (perms) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005985
Steve French0d817bc2008-05-22 02:02:03 +00005986 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005987 if (rc == -EAGAIN)
5988 goto setPermsRetry;
5989 return rc;
5990}
5991
Linus Torvalds1da177e2005-04-16 15:20:36 -07005992#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05005993/*
5994 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
5995 * function used by listxattr and getxattr type calls. When ea_name is set,
5996 * it looks for that attribute name and stuffs that value into the EAData
5997 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
5998 * buffer. In both cases, the return value is either the length of the
5999 * resulting data or a negative error code. If EAData is a NULL pointer then
6000 * the data isn't copied to it, but the length is returned.
6001 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006002ssize_t
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006003CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05006004 const unsigned char *searchName, const unsigned char *ea_name,
6005 char *EAData, size_t buf_size,
6006 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006007{
6008 /* BB assumes one setup word */
6009 TRANSACTION2_QPI_REQ *pSMB = NULL;
6010 TRANSACTION2_QPI_RSP *pSMBr = NULL;
6011 int rc = 0;
6012 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05006013 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006014 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00006015 struct fea *temp_fea;
6016 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006017 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006018 __u16 params, byte_count, data_offset;
Jeff Layton5980fc92011-07-28 12:48:26 -04006019 unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006020
Joe Perchesb6b38f72010-04-21 03:50:45 +00006021 cFYI(1, "In Query All EAs path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006022QAllEAsRetry:
6023 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6024 (void **) &pSMBr);
6025 if (rc)
6026 return rc;
6027
6028 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05006029 list_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006030 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
6031 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05006032 list_len++; /* trailing null */
6033 list_len *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006034 } else { /* BB improve the check for buffer overruns BB */
Jeff Layton6e462b92010-02-10 16:18:26 -05006035 list_len = strnlen(searchName, PATH_MAX);
6036 list_len++; /* trailing null */
6037 strncpy(pSMB->FileName, searchName, list_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006038 }
6039
Jeff Layton6e462b92010-02-10 16:18:26 -05006040 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006041 pSMB->TotalDataCount = 0;
6042 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006043 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05006044 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006045 pSMB->MaxSetupCount = 0;
6046 pSMB->Reserved = 0;
6047 pSMB->Flags = 0;
6048 pSMB->Timeout = 0;
6049 pSMB->Reserved2 = 0;
6050 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00006051 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006052 pSMB->DataCount = 0;
6053 pSMB->DataOffset = 0;
6054 pSMB->SetupCount = 1;
6055 pSMB->Reserved3 = 0;
6056 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
6057 byte_count = params + 1 /* pad */ ;
6058 pSMB->TotalParameterCount = cpu_to_le16(params);
6059 pSMB->ParameterCount = pSMB->TotalParameterCount;
6060 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
6061 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006062 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006063 pSMB->ByteCount = cpu_to_le16(byte_count);
6064
6065 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6066 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6067 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006068 cFYI(1, "Send error in QueryAllEAs = %d", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05006069 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006070 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006071
6072
6073 /* BB also check enough total bytes returned */
6074 /* BB we need to improve the validity checking
6075 of these trans2 responses */
6076
6077 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Jeff Layton820a8032011-05-04 08:05:26 -04006078 if (rc || get_bcc(&pSMBr->hdr) < 4) {
Jeff Laytonf0d38682010-02-10 16:18:26 -05006079 rc = -EIO; /* bad smb */
6080 goto QAllEAsOut;
6081 }
6082
6083 /* check that length of list is not more than bcc */
6084 /* check that each entry does not go beyond length
6085 of list */
6086 /* check that each element of each entry does not
6087 go beyond end of list */
6088 /* validate_trans2_offsets() */
6089 /* BB check if start of smb + data_offset > &bcc+ bcc */
6090
6091 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
6092 ea_response_data = (struct fealist *)
6093 (((char *) &pSMBr->hdr.Protocol) + data_offset);
6094
Jeff Layton6e462b92010-02-10 16:18:26 -05006095 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesb6b38f72010-04-21 03:50:45 +00006096 cFYI(1, "ea length %d", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05006097 if (list_len <= 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006098 cFYI(1, "empty EA list returned from server");
Jeff Laytonf0d38682010-02-10 16:18:26 -05006099 goto QAllEAsOut;
6100 }
6101
Jeff Layton0cd126b2010-02-10 16:18:26 -05006102 /* make sure list_len doesn't go past end of SMB */
Jeff Layton690c5222011-01-20 13:36:51 -05006103 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
Jeff Layton0cd126b2010-02-10 16:18:26 -05006104 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006105 cFYI(1, "EA list appears to go beyond SMB");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006106 rc = -EIO;
6107 goto QAllEAsOut;
6108 }
6109
Jeff Laytonf0d38682010-02-10 16:18:26 -05006110 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05006111 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006112 temp_fea = ea_response_data->list;
6113 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05006114 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00006115 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006116 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006117
Jeff Layton6e462b92010-02-10 16:18:26 -05006118 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006119 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006120 /* make sure we can read name_len and value_len */
6121 if (list_len < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006122 cFYI(1, "EA entry goes beyond length of list");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006123 rc = -EIO;
6124 goto QAllEAsOut;
6125 }
6126
6127 name_len = temp_fea->name_len;
6128 value_len = le16_to_cpu(temp_fea->value_len);
6129 list_len -= name_len + 1 + value_len;
6130 if (list_len < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006131 cFYI(1, "EA entry goes beyond length of list");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006132 rc = -EIO;
6133 goto QAllEAsOut;
6134 }
6135
Jeff Layton31c05192010-02-10 16:18:26 -05006136 if (ea_name) {
Jeff Layton91d065c2011-07-26 18:23:47 -04006137 if (ea_name_len == name_len &&
Jeff Laytonac423442011-10-11 06:41:32 -04006138 memcmp(ea_name, temp_ptr, name_len) == 0) {
Jeff Layton31c05192010-02-10 16:18:26 -05006139 temp_ptr += name_len + 1;
6140 rc = value_len;
6141 if (buf_size == 0)
6142 goto QAllEAsOut;
6143 if ((size_t)value_len > buf_size) {
6144 rc = -ERANGE;
6145 goto QAllEAsOut;
6146 }
6147 memcpy(EAData, temp_ptr, value_len);
6148 goto QAllEAsOut;
6149 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006150 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05006151 /* account for prefix user. and trailing null */
6152 rc += (5 + 1 + name_len);
6153 if (rc < (int) buf_size) {
6154 memcpy(EAData, "user.", 5);
6155 EAData += 5;
6156 memcpy(EAData, temp_ptr, name_len);
6157 EAData += name_len;
6158 /* null terminate name */
6159 *EAData = 0;
6160 ++EAData;
6161 } else if (buf_size == 0) {
6162 /* skip copy - calc size only */
6163 } else {
6164 /* stop before overrun buffer */
6165 rc = -ERANGE;
6166 break;
6167 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006168 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05006169 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006170 temp_fea = (struct fea *)temp_ptr;
6171 }
6172
Jeff Layton31c05192010-02-10 16:18:26 -05006173 /* didn't find the named attribute */
6174 if (ea_name)
6175 rc = -ENODATA;
6176
Jeff Laytonf0d38682010-02-10 16:18:26 -05006177QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00006178 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006179 if (rc == -EAGAIN)
6180 goto QAllEAsRetry;
6181
6182 return (ssize_t)rc;
6183}
6184
Linus Torvalds1da177e2005-04-16 15:20:36 -07006185int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006186CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
6187 const char *fileName, const char *ea_name, const void *ea_value,
Steve French50c2f752007-07-13 00:33:32 +00006188 const __u16 ea_value_len, const struct nls_table *nls_codepage,
6189 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006190{
6191 struct smb_com_transaction2_spi_req *pSMB = NULL;
6192 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
6193 struct fealist *parm_data;
6194 int name_len;
6195 int rc = 0;
6196 int bytes_returned = 0;
6197 __u16 params, param_offset, byte_count, offset, count;
6198
Joe Perchesb6b38f72010-04-21 03:50:45 +00006199 cFYI(1, "In SetEA");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006200SetEARetry:
6201 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6202 (void **) &pSMBr);
6203 if (rc)
6204 return rc;
6205
6206 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6207 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006208 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
6209 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006210 name_len++; /* trailing null */
6211 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00006212 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006213 name_len = strnlen(fileName, PATH_MAX);
6214 name_len++; /* trailing null */
6215 strncpy(pSMB->FileName, fileName, name_len);
6216 }
6217
6218 params = 6 + name_len;
6219
6220 /* done calculating parms using name_len of file name,
6221 now use name_len to calculate length of ea name
6222 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00006223 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006224 name_len = 0;
6225 else
Steve French50c2f752007-07-13 00:33:32 +00006226 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006227
Steve Frenchdae5dbd2007-12-30 23:49:57 +00006228 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006229 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006230 /* BB find max SMB PDU from sess */
6231 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006232 pSMB->MaxSetupCount = 0;
6233 pSMB->Reserved = 0;
6234 pSMB->Flags = 0;
6235 pSMB->Timeout = 0;
6236 pSMB->Reserved2 = 0;
6237 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006238 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006239 offset = param_offset + params;
6240 pSMB->InformationLevel =
6241 cpu_to_le16(SMB_SET_FILE_EA);
6242
6243 parm_data =
6244 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
6245 offset);
6246 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6247 pSMB->DataOffset = cpu_to_le16(offset);
6248 pSMB->SetupCount = 1;
6249 pSMB->Reserved3 = 0;
6250 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6251 byte_count = 3 /* pad */ + params + count;
6252 pSMB->DataCount = cpu_to_le16(count);
6253 parm_data->list_len = cpu_to_le32(count);
6254 parm_data->list[0].EA_flags = 0;
6255 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08006256 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006257 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00006258 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00006259 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006260 parm_data->list[0].name[name_len] = 0;
6261 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
6262 /* caller ensures that ea_value_len is less than 64K but
6263 we need to ensure that it fits within the smb */
6264
Steve French50c2f752007-07-13 00:33:32 +00006265 /*BB add length check to see if it would fit in
6266 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00006267 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
6268 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00006269 memcpy(parm_data->list[0].name+name_len+1,
6270 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006271
6272 pSMB->TotalDataCount = pSMB->DataCount;
6273 pSMB->ParameterCount = cpu_to_le16(params);
6274 pSMB->TotalParameterCount = pSMB->ParameterCount;
6275 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006276 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006277 pSMB->ByteCount = cpu_to_le16(byte_count);
6278 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6279 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006280 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00006281 cFYI(1, "SetPathInfo (EA) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006282
6283 cifs_buf_release(pSMB);
6284
6285 if (rc == -EAGAIN)
6286 goto SetEARetry;
6287
6288 return rc;
6289}
Linus Torvalds1da177e2005-04-16 15:20:36 -07006290#endif
Steve French0eff0e22011-02-24 05:39:23 +00006291
6292#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */
6293/*
6294 * Years ago the kernel added a "dnotify" function for Samba server,
6295 * to allow network clients (such as Windows) to display updated
6296 * lists of files in directory listings automatically when
6297 * files are added by one user when another user has the
6298 * same directory open on their desktop. The Linux cifs kernel
6299 * client hooked into the kernel side of this interface for
6300 * the same reason, but ironically when the VFS moved from
6301 * "dnotify" to "inotify" it became harder to plug in Linux
6302 * network file system clients (the most obvious use case
6303 * for notify interfaces is when multiple users can update
6304 * the contents of the same directory - exactly what network
6305 * file systems can do) although the server (Samba) could
6306 * still use it. For the short term we leave the worker
6307 * function ifdeffed out (below) until inotify is fixed
6308 * in the VFS to make it easier to plug in network file
6309 * system clients. If inotify turns out to be permanently
6310 * incompatible for network fs clients, we could instead simply
6311 * expose this config flag by adding a future cifs (and smb2) notify ioctl.
6312 */
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006313int CIFSSMBNotify(const unsigned int xid, struct cifs_tcon *tcon,
Steve French0eff0e22011-02-24 05:39:23 +00006314 const int notify_subdirs, const __u16 netfid,
6315 __u32 filter, struct file *pfile, int multishot,
6316 const struct nls_table *nls_codepage)
6317{
6318 int rc = 0;
6319 struct smb_com_transaction_change_notify_req *pSMB = NULL;
6320 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
6321 struct dir_notify_req *dnotify_req;
6322 int bytes_returned;
6323
6324 cFYI(1, "In CIFSSMBNotify for file handle %d", (int)netfid);
6325 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
6326 (void **) &pSMBr);
6327 if (rc)
6328 return rc;
6329
6330 pSMB->TotalParameterCount = 0 ;
6331 pSMB->TotalDataCount = 0;
6332 pSMB->MaxParameterCount = cpu_to_le32(2);
Jeff Laytonc974bef2011-10-11 06:41:32 -04006333 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Steve French0eff0e22011-02-24 05:39:23 +00006334 pSMB->MaxSetupCount = 4;
6335 pSMB->Reserved = 0;
6336 pSMB->ParameterOffset = 0;
6337 pSMB->DataCount = 0;
6338 pSMB->DataOffset = 0;
6339 pSMB->SetupCount = 4; /* single byte does not need le conversion */
6340 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
6341 pSMB->ParameterCount = pSMB->TotalParameterCount;
6342 if (notify_subdirs)
6343 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
6344 pSMB->Reserved2 = 0;
6345 pSMB->CompletionFilter = cpu_to_le32(filter);
6346 pSMB->Fid = netfid; /* file handle always le */
6347 pSMB->ByteCount = 0;
6348
6349 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6350 (struct smb_hdr *)pSMBr, &bytes_returned,
6351 CIFS_ASYNC_OP);
6352 if (rc) {
6353 cFYI(1, "Error in Notify = %d", rc);
6354 } else {
6355 /* Add file to outstanding requests */
6356 /* BB change to kmem cache alloc */
6357 dnotify_req = kmalloc(
6358 sizeof(struct dir_notify_req),
6359 GFP_KERNEL);
6360 if (dnotify_req) {
6361 dnotify_req->Pid = pSMB->hdr.Pid;
6362 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
6363 dnotify_req->Mid = pSMB->hdr.Mid;
6364 dnotify_req->Tid = pSMB->hdr.Tid;
6365 dnotify_req->Uid = pSMB->hdr.Uid;
6366 dnotify_req->netfid = netfid;
6367 dnotify_req->pfile = pfile;
6368 dnotify_req->filter = filter;
6369 dnotify_req->multishot = multishot;
6370 spin_lock(&GlobalMid_Lock);
6371 list_add_tail(&dnotify_req->lhead,
6372 &GlobalDnotifyReqList);
6373 spin_unlock(&GlobalMid_Lock);
6374 } else
6375 rc = -ENOMEM;
6376 }
6377 cifs_buf_release(pSMB);
6378 return rc;
6379}
6380#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */