blob: 733119dad4937c67e7973a60676234af547e40f4 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/cifssmb.c
3 *
Steve Frenchf19159d2010-04-21 04:12:10 +00004 * Copyright (C) International Business Machines Corp., 2002,2010
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * Author(s): Steve French (sfrench@us.ibm.com)
6 *
7 * Contains the routines for constructing the SMB PDUs themselves
8 *
9 * This library is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as published
11 * by the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
17 * the GNU Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24 /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c */
25 /* These are mostly routines that operate on a pathname, or on a tree id */
26 /* (mounted volume), but there are eight handle based routines which must be */
Steve French2dd29d32007-04-23 22:07:35 +000027 /* treated slightly differently for reconnection purposes since we never */
28 /* want to reuse a stale file handle and only the caller knows the file info */
Linus Torvalds1da177e2005-04-16 15:20:36 -070029
30#include <linux/fs.h>
31#include <linux/kernel.h>
32#include <linux/vfs.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090033#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include <linux/posix_acl_xattr.h>
Jeff Laytonc28c89f2011-05-19 16:22:56 -040035#include <linux/pagemap.h>
Jeff Laytone28bc5b2011-10-19 15:30:07 -040036#include <linux/swap.h>
37#include <linux/task_io_accounting_ops.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070038#include <asm/uaccess.h>
39#include "cifspdu.h"
40#include "cifsglob.h"
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +000041#include "cifsacl.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070042#include "cifsproto.h"
43#include "cifs_unicode.h"
44#include "cifs_debug.h"
Jeff Laytone28bc5b2011-10-19 15:30:07 -040045#include "fscache.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070046
47#ifdef CONFIG_CIFS_POSIX
48static struct {
49 int index;
50 char *name;
51} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000052#ifdef CONFIG_CIFS_WEAK_PW_HASH
53 {LANMAN_PROT, "\2LM1.2X002"},
Steve French9ac00b72006-09-30 04:13:17 +000054 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000055#endif /* weak password hashing for legacy clients */
Steve French50c2f752007-07-13 00:33:32 +000056 {CIFS_PROT, "\2NT LM 0.12"},
Steve French39798772006-05-31 22:40:51 +000057 {POSIX_PROT, "\2POSIX 2"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070058 {BAD_PROT, "\2"}
59};
60#else
61static struct {
62 int index;
63 char *name;
64} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000065#ifdef CONFIG_CIFS_WEAK_PW_HASH
66 {LANMAN_PROT, "\2LM1.2X002"},
Steve French18f75ca2006-10-01 03:13:01 +000067 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000068#endif /* weak password hashing for legacy clients */
Steve French790fe572007-07-07 19:25:05 +000069 {CIFS_PROT, "\2NT LM 0.12"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070070 {BAD_PROT, "\2"}
71};
72#endif
73
Steve French39798772006-05-31 22:40:51 +000074/* define the number of elements in the cifs dialect array */
75#ifdef CONFIG_CIFS_POSIX
76#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000077#define CIFS_NUM_PROT 4
Steve French39798772006-05-31 22:40:51 +000078#else
79#define CIFS_NUM_PROT 2
80#endif /* CIFS_WEAK_PW_HASH */
81#else /* not posix */
82#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000083#define CIFS_NUM_PROT 3
Steve French39798772006-05-31 22:40:51 +000084#else
85#define CIFS_NUM_PROT 1
86#endif /* CONFIG_CIFS_WEAK_PW_HASH */
87#endif /* CIFS_POSIX */
88
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +040089/*
90 * Mark as invalid, all open files on tree connections since they
91 * were closed when session to server was lost.
92 */
93void
94cifs_mark_open_files_invalid(struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -070095{
96 struct cifsFileInfo *open_file = NULL;
Steve French790fe572007-07-07 19:25:05 +000097 struct list_head *tmp;
98 struct list_head *tmp1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070099
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400100 /* list all files open on tree connection and mark them invalid */
Jeff Layton44772882010-10-15 15:34:03 -0400101 spin_lock(&cifs_file_list_lock);
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400102 list_for_each_safe(tmp, tmp1, &tcon->openFileList) {
Steve French790fe572007-07-07 19:25:05 +0000103 open_file = list_entry(tmp, struct cifsFileInfo, tlist);
Steve Frenchad8b15f2008-08-08 21:10:16 +0000104 open_file->invalidHandle = true;
Jeff Layton3bc303c2009-09-21 06:47:50 -0400105 open_file->oplock_break_cancelled = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106 }
Jeff Layton44772882010-10-15 15:34:03 -0400107 spin_unlock(&cifs_file_list_lock);
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400108 /*
109 * BB Add call to invalidate_inodes(sb) for all superblocks mounted
110 * to this tcon.
111 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112}
113
Jeff Layton9162ab22009-09-03 12:07:17 -0400114/* reconnect the socket, tcon, and smb session if needed */
115static int
Steve French96daf2b2011-05-27 04:34:02 +0000116cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
Jeff Layton9162ab22009-09-03 12:07:17 -0400117{
Jeff Laytonc4a55342011-07-28 12:40:36 -0400118 int rc;
Steve French96daf2b2011-05-27 04:34:02 +0000119 struct cifs_ses *ses;
Jeff Layton9162ab22009-09-03 12:07:17 -0400120 struct TCP_Server_Info *server;
121 struct nls_table *nls_codepage;
122
123 /*
124 * SMBs NegProt, SessSetup, uLogoff do not have tcon yet so check for
125 * tcp and smb session status done differently for those three - in the
126 * calling routine
127 */
128 if (!tcon)
129 return 0;
130
131 ses = tcon->ses;
132 server = ses->server;
133
134 /*
135 * only tree disconnect, open, and write, (and ulogoff which does not
136 * have tcon) are allowed as we start force umount
137 */
138 if (tcon->tidStatus == CifsExiting) {
139 if (smb_command != SMB_COM_WRITE_ANDX &&
140 smb_command != SMB_COM_OPEN_ANDX &&
141 smb_command != SMB_COM_TREE_DISCONNECT) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000142 cFYI(1, "can not send cmd %d while umounting",
143 smb_command);
Jeff Layton9162ab22009-09-03 12:07:17 -0400144 return -ENODEV;
145 }
146 }
147
Jeff Layton9162ab22009-09-03 12:07:17 -0400148 /*
149 * Give demultiplex thread up to 10 seconds to reconnect, should be
150 * greater than cifs socket timeout which is 7 seconds
151 */
152 while (server->tcpStatus == CifsNeedReconnect) {
153 wait_event_interruptible_timeout(server->response_q,
Steve Frenchfd88ce92011-04-12 01:01:14 +0000154 (server->tcpStatus != CifsNeedReconnect), 10 * HZ);
Jeff Layton9162ab22009-09-03 12:07:17 -0400155
Steve Frenchfd88ce92011-04-12 01:01:14 +0000156 /* are we still trying to reconnect? */
Jeff Layton9162ab22009-09-03 12:07:17 -0400157 if (server->tcpStatus != CifsNeedReconnect)
158 break;
159
160 /*
161 * on "soft" mounts we wait once. Hard mounts keep
162 * retrying until process is killed or server comes
163 * back on-line
164 */
Jeff Laytond4025392011-02-07 08:54:35 -0500165 if (!tcon->retry) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000166 cFYI(1, "gave up waiting on reconnect in smb_init");
Jeff Layton9162ab22009-09-03 12:07:17 -0400167 return -EHOSTDOWN;
168 }
169 }
170
171 if (!ses->need_reconnect && !tcon->need_reconnect)
172 return 0;
173
174 nls_codepage = load_nls_default();
175
176 /*
177 * need to prevent multiple threads trying to simultaneously
178 * reconnect the same SMB session
179 */
Steve Frenchd7b619c2010-02-25 05:36:46 +0000180 mutex_lock(&ses->session_mutex);
Jeff Layton198b5682010-04-24 07:57:48 -0400181 rc = cifs_negotiate_protocol(0, ses);
182 if (rc == 0 && ses->need_reconnect)
Jeff Layton9162ab22009-09-03 12:07:17 -0400183 rc = cifs_setup_session(0, ses, nls_codepage);
184
185 /* do we need to reconnect tcon? */
186 if (rc || !tcon->need_reconnect) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000187 mutex_unlock(&ses->session_mutex);
Jeff Layton9162ab22009-09-03 12:07:17 -0400188 goto out;
189 }
190
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400191 cifs_mark_open_files_invalid(tcon);
Jeff Layton9162ab22009-09-03 12:07:17 -0400192 rc = CIFSTCon(0, ses, tcon->treeName, tcon, nls_codepage);
Steve Frenchd7b619c2010-02-25 05:36:46 +0000193 mutex_unlock(&ses->session_mutex);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000194 cFYI(1, "reconnect tcon rc = %d", rc);
Jeff Layton9162ab22009-09-03 12:07:17 -0400195
196 if (rc)
197 goto out;
198
199 /*
200 * FIXME: check if wsize needs updated due to negotiated smb buffer
201 * size shrinking
202 */
203 atomic_inc(&tconInfoReconnectCount);
204
205 /* tell server Unix caps we support */
206 if (ses->capabilities & CAP_UNIX)
207 reset_cifs_unix_caps(0, tcon, NULL, NULL);
208
209 /*
210 * Removed call to reopen open files here. It is safer (and faster) to
211 * reopen files one at a time as needed in read and write.
212 *
213 * FIXME: what about file locks? don't we need to reclaim them ASAP?
214 */
215
216out:
217 /*
218 * Check if handle based operation so we know whether we can continue
219 * or not without returning to caller to reset file handle
220 */
221 switch (smb_command) {
222 case SMB_COM_READ_ANDX:
223 case SMB_COM_WRITE_ANDX:
224 case SMB_COM_CLOSE:
225 case SMB_COM_FIND_CLOSE2:
226 case SMB_COM_LOCKING_ANDX:
227 rc = -EAGAIN;
228 }
229
230 unload_nls(nls_codepage);
231 return rc;
232}
233
Steve Frenchad7a2922008-02-07 23:25:02 +0000234/* Allocate and return pointer to an SMB request buffer, and set basic
235 SMB information in the SMB header. If the return code is zero, this
236 function must have filled in request_buf pointer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237static int
Steve French96daf2b2011-05-27 04:34:02 +0000238small_smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000239 void **request_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240{
Jeff Laytonf5695992010-09-29 15:27:08 -0400241 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242
Jeff Layton9162ab22009-09-03 12:07:17 -0400243 rc = cifs_reconnect_tcon(tcon, smb_command);
Steve French790fe572007-07-07 19:25:05 +0000244 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245 return rc;
246
247 *request_buf = cifs_small_buf_get();
248 if (*request_buf == NULL) {
249 /* BB should we add a retry in here if not a writepage? */
250 return -ENOMEM;
251 }
252
Steve French63135e02007-07-17 17:34:02 +0000253 header_assemble((struct smb_hdr *) *request_buf, smb_command,
Steve Frenchc18c8422007-07-18 23:21:09 +0000254 tcon, wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255
Steve French790fe572007-07-07 19:25:05 +0000256 if (tcon != NULL)
257 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700258
Jeff Laytonf5695992010-09-29 15:27:08 -0400259 return 0;
Steve French5815449d2006-02-14 01:36:20 +0000260}
261
Steve French12b3b8f2006-02-09 21:12:47 +0000262int
Steve French50c2f752007-07-13 00:33:32 +0000263small_smb_init_no_tc(const int smb_command, const int wct,
Steve French96daf2b2011-05-27 04:34:02 +0000264 struct cifs_ses *ses, void **request_buf)
Steve French12b3b8f2006-02-09 21:12:47 +0000265{
266 int rc;
Steve French50c2f752007-07-13 00:33:32 +0000267 struct smb_hdr *buffer;
Steve French12b3b8f2006-02-09 21:12:47 +0000268
Steve French5815449d2006-02-14 01:36:20 +0000269 rc = small_smb_init(smb_command, wct, NULL, request_buf);
Steve French790fe572007-07-07 19:25:05 +0000270 if (rc)
Steve French12b3b8f2006-02-09 21:12:47 +0000271 return rc;
272
Steve French04fdabe2006-02-10 05:52:50 +0000273 buffer = (struct smb_hdr *)*request_buf;
Pavel Shilovsky88257362012-05-23 14:01:59 +0400274 buffer->Mid = get_next_mid(ses->server);
Steve French12b3b8f2006-02-09 21:12:47 +0000275 if (ses->capabilities & CAP_UNICODE)
276 buffer->Flags2 |= SMBFLG2_UNICODE;
Steve French04fdabe2006-02-10 05:52:50 +0000277 if (ses->capabilities & CAP_STATUS32)
Steve French12b3b8f2006-02-09 21:12:47 +0000278 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
279
280 /* uid, tid can stay at zero as set in header assemble */
281
Steve French50c2f752007-07-13 00:33:32 +0000282 /* BB add support for turning on the signing when
Steve French12b3b8f2006-02-09 21:12:47 +0000283 this function is used after 1st of session setup requests */
284
285 return rc;
286}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287
288/* If the return code is zero, this function must fill in request_buf pointer */
289static int
Steve French96daf2b2011-05-27 04:34:02 +0000290__smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400291 void **request_buf, void **response_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293 *request_buf = cifs_buf_get();
294 if (*request_buf == NULL) {
295 /* BB should we add a retry in here if not a writepage? */
296 return -ENOMEM;
297 }
298 /* Although the original thought was we needed the response buf for */
299 /* potential retries of smb operations it turns out we can determine */
300 /* from the mid flags when the request buffer can be resent without */
301 /* having to use a second distinct buffer for the response */
Steve French790fe572007-07-07 19:25:05 +0000302 if (response_buf)
Steve French50c2f752007-07-13 00:33:32 +0000303 *response_buf = *request_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304
305 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000306 wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307
Steve French790fe572007-07-07 19:25:05 +0000308 if (tcon != NULL)
309 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700310
Jeff Laytonf5695992010-09-29 15:27:08 -0400311 return 0;
312}
313
314/* If the return code is zero, this function must fill in request_buf pointer */
315static int
Steve French96daf2b2011-05-27 04:34:02 +0000316smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400317 void **request_buf, void **response_buf)
318{
319 int rc;
320
321 rc = cifs_reconnect_tcon(tcon, smb_command);
322 if (rc)
323 return rc;
324
325 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
326}
327
328static int
Steve French96daf2b2011-05-27 04:34:02 +0000329smb_init_no_reconnect(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400330 void **request_buf, void **response_buf)
331{
332 if (tcon->ses->need_reconnect || tcon->need_reconnect)
333 return -EHOSTDOWN;
334
335 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336}
337
Steve French50c2f752007-07-13 00:33:32 +0000338static int validate_t2(struct smb_t2_rsp *pSMB)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339{
Jeff Layton12df83c2011-01-20 13:36:51 -0500340 unsigned int total_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341
Jeff Layton12df83c2011-01-20 13:36:51 -0500342 /* check for plausible wct */
343 if (pSMB->hdr.WordCount < 10)
344 goto vt2_err;
345
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346 /* check for parm and data offset going beyond end of smb */
Jeff Layton12df83c2011-01-20 13:36:51 -0500347 if (get_unaligned_le16(&pSMB->t2_rsp.ParameterOffset) > 1024 ||
348 get_unaligned_le16(&pSMB->t2_rsp.DataOffset) > 1024)
349 goto vt2_err;
350
Jeff Layton12df83c2011-01-20 13:36:51 -0500351 total_size = get_unaligned_le16(&pSMB->t2_rsp.ParameterCount);
352 if (total_size >= 512)
353 goto vt2_err;
354
Jeff Laytonfd5707e2011-03-31 17:22:07 -0400355 /* check that bcc is at least as big as parms + data, and that it is
356 * less than negotiated smb buffer
357 */
Jeff Layton12df83c2011-01-20 13:36:51 -0500358 total_size += get_unaligned_le16(&pSMB->t2_rsp.DataCount);
359 if (total_size > get_bcc(&pSMB->hdr) ||
360 total_size >= CIFSMaxBufSize + MAX_CIFS_HDR_SIZE)
361 goto vt2_err;
362
363 return 0;
364vt2_err:
Steve French50c2f752007-07-13 00:33:32 +0000365 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 sizeof(struct smb_t2_rsp) + 16);
Jeff Layton12df83c2011-01-20 13:36:51 -0500367 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368}
Jeff Layton690c5222011-01-20 13:36:51 -0500369
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370int
Pavel Shilovsky286170a2012-05-25 10:43:58 +0400371CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372{
373 NEGOTIATE_REQ *pSMB;
374 NEGOTIATE_RSP *pSMBr;
375 int rc = 0;
376 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000377 int i;
Steve French50c2f752007-07-13 00:33:32 +0000378 struct TCP_Server_Info *server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 u16 count;
Steve French750d1152006-06-27 06:28:30 +0000380 unsigned int secFlags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381
Steve French790fe572007-07-07 19:25:05 +0000382 if (ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 server = ses->server;
384 else {
385 rc = -EIO;
386 return rc;
387 }
388 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
389 (void **) &pSMB, (void **) &pSMBr);
390 if (rc)
391 return rc;
Steve French750d1152006-06-27 06:28:30 +0000392
393 /* if any of auth flags (ie not sign or seal) are overriden use them */
Steve French790fe572007-07-07 19:25:05 +0000394 if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
Steve French762e5ab2007-06-28 18:41:42 +0000395 secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
Steve French750d1152006-06-27 06:28:30 +0000396 else /* if override flags set only sign/seal OR them with global auth */
Jeff Layton04912d62010-04-24 07:57:45 -0400397 secFlags = global_secflags | ses->overrideSecFlg;
Steve French750d1152006-06-27 06:28:30 +0000398
Joe Perchesb6b38f72010-04-21 03:50:45 +0000399 cFYI(1, "secFlags 0x%x", secFlags);
Steve Frenchf40c5622006-06-28 00:13:38 +0000400
Pavel Shilovsky88257362012-05-23 14:01:59 +0400401 pSMB->hdr.Mid = get_next_mid(server);
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000402 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
Steve Frencha0136892007-10-04 20:05:09 +0000403
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000404 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
Steve French254e55e2006-06-04 05:53:15 +0000405 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Steve Frencha0136892007-10-04 20:05:09 +0000406 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000407 cFYI(1, "Kerberos only mechanism, enable extended security");
Steve Frencha0136892007-10-04 20:05:09 +0000408 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Jeff Laytonb4d6fcf2011-01-07 11:30:28 -0500409 } else if ((secFlags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP)
Steve Frenchac683922009-05-06 04:16:04 +0000410 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
411 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_NTLMSSP) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000412 cFYI(1, "NTLMSSP only mechanism, enable extended security");
Steve Frenchac683922009-05-06 04:16:04 +0000413 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
414 }
Steve French50c2f752007-07-13 00:33:32 +0000415
Steve French39798772006-05-31 22:40:51 +0000416 count = 0;
Steve French50c2f752007-07-13 00:33:32 +0000417 for (i = 0; i < CIFS_NUM_PROT; i++) {
Steve French39798772006-05-31 22:40:51 +0000418 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
419 count += strlen(protocols[i].name) + 1;
420 /* null at end of source and target buffers anyway */
421 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000422 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 pSMB->ByteCount = cpu_to_le16(count);
424
425 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
426 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French50c2f752007-07-13 00:33:32 +0000427 if (rc != 0)
Steve French254e55e2006-06-04 05:53:15 +0000428 goto neg_err_exit;
429
Jeff Layton9bf67e52010-04-24 07:57:46 -0400430 server->dialect = le16_to_cpu(pSMBr->DialectIndex);
431 cFYI(1, "Dialect: %d", server->dialect);
Steve French254e55e2006-06-04 05:53:15 +0000432 /* Check wct = 1 error case */
Jeff Layton9bf67e52010-04-24 07:57:46 -0400433 if ((pSMBr->hdr.WordCount < 13) || (server->dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000434 /* core returns wct = 1, but we do not ask for core - otherwise
Steve French50c2f752007-07-13 00:33:32 +0000435 small wct just comes when dialect index is -1 indicating we
Steve French254e55e2006-06-04 05:53:15 +0000436 could not negotiate a common dialect */
437 rc = -EOPNOTSUPP;
438 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000439#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French790fe572007-07-07 19:25:05 +0000440 } else if ((pSMBr->hdr.WordCount == 13)
Jeff Layton9bf67e52010-04-24 07:57:46 -0400441 && ((server->dialect == LANMAN_PROT)
442 || (server->dialect == LANMAN2_PROT))) {
Steve Frenchb815f1e52006-10-02 05:53:29 +0000443 __s16 tmp;
Steve French50c2f752007-07-13 00:33:32 +0000444 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
Steve French254e55e2006-06-04 05:53:15 +0000445
Steve French790fe572007-07-07 19:25:05 +0000446 if ((secFlags & CIFSSEC_MAY_LANMAN) ||
Steve French750d1152006-06-27 06:28:30 +0000447 (secFlags & CIFSSEC_MAY_PLNTXT))
Steve French254e55e2006-06-04 05:53:15 +0000448 server->secType = LANMAN;
449 else {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000450 cERROR(1, "mount failed weak security disabled"
451 " in /proc/fs/cifs/SecurityFlags");
Steve French39798772006-05-31 22:40:51 +0000452 rc = -EOPNOTSUPP;
453 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000454 }
Pavel Shilovsky286170a2012-05-25 10:43:58 +0400455 server->sec_mode = le16_to_cpu(rsp->SecurityMode);
Pavel Shilovsky10b9b982012-03-20 12:55:09 +0300456 server->maxReq = min_t(unsigned int,
457 le16_to_cpu(rsp->MaxMpxCount),
458 cifs_max_pending);
Pavel Shilovsky45275782012-05-17 17:53:29 +0400459 set_credits(server, server->maxReq);
Jeff Laytonc974bef2011-10-11 06:41:32 -0400460 server->maxBuf = le16_to_cpu(rsp->MaxBufSize);
Steve Frencheca6acf2009-02-20 05:43:09 +0000461 server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
Steve French254e55e2006-06-04 05:53:15 +0000462 /* even though we do not use raw we might as well set this
463 accurately, in case we ever find a need for it */
Steve French790fe572007-07-07 19:25:05 +0000464 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
Steve Frencheca6acf2009-02-20 05:43:09 +0000465 server->max_rw = 0xFF00;
Steve French254e55e2006-06-04 05:53:15 +0000466 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
467 } else {
Steve Frencheca6acf2009-02-20 05:43:09 +0000468 server->max_rw = 0;/* do not need to use raw anyway */
Steve French254e55e2006-06-04 05:53:15 +0000469 server->capabilities = CAP_MPX_MODE;
470 }
Steve Frenchb815f1e52006-10-02 05:53:29 +0000471 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
Steve French1a70d652006-10-02 05:59:18 +0000472 if (tmp == -1) {
Steve French25ee4a92006-09-30 00:54:23 +0000473 /* OS/2 often does not set timezone therefore
474 * we must use server time to calc time zone.
Steve Frenchb815f1e52006-10-02 05:53:29 +0000475 * Could deviate slightly from the right zone.
476 * Smallest defined timezone difference is 15 minutes
477 * (i.e. Nepal). Rounding up/down is done to match
478 * this requirement.
Steve French25ee4a92006-09-30 00:54:23 +0000479 */
Steve Frenchb815f1e52006-10-02 05:53:29 +0000480 int val, seconds, remain, result;
Steve French25ee4a92006-09-30 00:54:23 +0000481 struct timespec ts, utc;
482 utc = CURRENT_TIME;
Jeff Laytonc4a2c082009-05-27 09:37:33 -0400483 ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
484 rsp->SrvTime.Time, 0);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000485 cFYI(1, "SrvTime %d sec since 1970 (utc: %d) diff: %d",
Steve French50c2f752007-07-13 00:33:32 +0000486 (int)ts.tv_sec, (int)utc.tv_sec,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000487 (int)(utc.tv_sec - ts.tv_sec));
Steve Frenchb815f1e52006-10-02 05:53:29 +0000488 val = (int)(utc.tv_sec - ts.tv_sec);
Andre Haupt8594c152007-08-30 20:18:41 +0000489 seconds = abs(val);
Steve French947a5062006-10-02 05:55:25 +0000490 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
Steve Frenchb815f1e52006-10-02 05:53:29 +0000491 remain = seconds % MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000492 if (remain >= (MIN_TZ_ADJ / 2))
Steve Frenchb815f1e52006-10-02 05:53:29 +0000493 result += MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000494 if (val < 0)
Steve Frenchad7a2922008-02-07 23:25:02 +0000495 result = -result;
Steve Frenchb815f1e52006-10-02 05:53:29 +0000496 server->timeAdj = result;
Steve French25ee4a92006-09-30 00:54:23 +0000497 } else {
Steve Frenchb815f1e52006-10-02 05:53:29 +0000498 server->timeAdj = (int)tmp;
499 server->timeAdj *= 60; /* also in seconds */
Steve French25ee4a92006-09-30 00:54:23 +0000500 }
Joe Perchesb6b38f72010-04-21 03:50:45 +0000501 cFYI(1, "server->timeAdj: %d seconds", server->timeAdj);
Steve French25ee4a92006-09-30 00:54:23 +0000502
Steve French39798772006-05-31 22:40:51 +0000503
Steve French254e55e2006-06-04 05:53:15 +0000504 /* BB get server time for time conversions and add
Steve French50c2f752007-07-13 00:33:32 +0000505 code to use it and timezone since this is not UTC */
Steve French39798772006-05-31 22:40:51 +0000506
Steve French50c2f752007-07-13 00:33:32 +0000507 if (rsp->EncryptionKeyLength ==
Steve French25ee4a92006-09-30 00:54:23 +0000508 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500509 memcpy(ses->server->cryptkey, rsp->EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000510 CIFS_CRYPTO_KEY_SIZE);
Steve French96daf2b2011-05-27 04:34:02 +0000511 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
Steve French254e55e2006-06-04 05:53:15 +0000512 rc = -EIO; /* need cryptkey unless plain text */
513 goto neg_err_exit;
514 }
Steve French39798772006-05-31 22:40:51 +0000515
Steve Frenchf19159d2010-04-21 04:12:10 +0000516 cFYI(1, "LANMAN negotiated");
Steve French254e55e2006-06-04 05:53:15 +0000517 /* we will not end up setting signing flags - as no signing
518 was in LANMAN and server did not return the flags on */
519 goto signing_check;
Steve French7c7b25b2006-06-01 19:20:10 +0000520#else /* weak security disabled */
Steve French790fe572007-07-07 19:25:05 +0000521 } else if (pSMBr->hdr.WordCount == 13) {
Steve Frenchf19159d2010-04-21 04:12:10 +0000522 cERROR(1, "mount failed, cifs module not built "
523 "with CIFS_WEAK_PW_HASH support");
Dan Carpenter8212cf72010-03-15 11:22:26 +0300524 rc = -EOPNOTSUPP;
Steve French7c7b25b2006-06-01 19:20:10 +0000525#endif /* WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000526 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000527 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000528 /* unknown wct */
529 rc = -EOPNOTSUPP;
530 goto neg_err_exit;
531 }
532 /* else wct == 17 NTLM */
Steve French96daf2b2011-05-27 04:34:02 +0000533 server->sec_mode = pSMBr->SecurityMode;
534 if ((server->sec_mode & SECMODE_USER) == 0)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000535 cFYI(1, "share mode security");
Steve French39798772006-05-31 22:40:51 +0000536
Steve French96daf2b2011-05-27 04:34:02 +0000537 if ((server->sec_mode & SECMODE_PW_ENCRYPT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000538#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French750d1152006-06-27 06:28:30 +0000539 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000540#endif /* CIFS_WEAK_PW_HASH */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000541 cERROR(1, "Server requests plain text password"
542 " but client support disabled");
Steve French9312f672006-06-04 22:21:07 +0000543
Steve French790fe572007-07-07 19:25:05 +0000544 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
Steve French254e55e2006-06-04 05:53:15 +0000545 server->secType = NTLMv2;
Steve French790fe572007-07-07 19:25:05 +0000546 else if (secFlags & CIFSSEC_MAY_NTLM)
Steve French254e55e2006-06-04 05:53:15 +0000547 server->secType = NTLM;
Steve French790fe572007-07-07 19:25:05 +0000548 else if (secFlags & CIFSSEC_MAY_NTLMV2)
Steve Frenchf40c5622006-06-28 00:13:38 +0000549 server->secType = NTLMv2;
Steve Frencha0136892007-10-04 20:05:09 +0000550 else if (secFlags & CIFSSEC_MAY_KRB5)
551 server->secType = Kerberos;
Steve Frenchac683922009-05-06 04:16:04 +0000552 else if (secFlags & CIFSSEC_MAY_NTLMSSP)
Steve Frenchf46c7232009-06-25 03:04:20 +0000553 server->secType = RawNTLMSSP;
Steve Frencha0136892007-10-04 20:05:09 +0000554 else if (secFlags & CIFSSEC_MAY_LANMAN)
555 server->secType = LANMAN;
Steve Frencha0136892007-10-04 20:05:09 +0000556 else {
557 rc = -EOPNOTSUPP;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000558 cERROR(1, "Invalid security type");
Steve Frencha0136892007-10-04 20:05:09 +0000559 goto neg_err_exit;
560 }
561 /* else ... any others ...? */
Steve French7c7b25b2006-06-01 19:20:10 +0000562
Steve French254e55e2006-06-04 05:53:15 +0000563 /* one byte, so no need to convert this or EncryptionKeyLen from
564 little endian */
Pavel Shilovsky10b9b982012-03-20 12:55:09 +0300565 server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount),
566 cifs_max_pending);
Pavel Shilovsky45275782012-05-17 17:53:29 +0400567 set_credits(server, server->maxReq);
Steve French254e55e2006-06-04 05:53:15 +0000568 /* probably no need to store and check maxvcs */
Jeff Laytonc974bef2011-10-11 06:41:32 -0400569 server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize);
Steve Frencheca6acf2009-02-20 05:43:09 +0000570 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000571 cFYI(DBG2, "Max buf = %d", ses->server->maxBuf);
Steve French254e55e2006-06-04 05:53:15 +0000572 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e52006-10-02 05:53:29 +0000573 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
574 server->timeAdj *= 60;
Steve French254e55e2006-06-04 05:53:15 +0000575 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500576 memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000577 CIFS_CRYPTO_KEY_SIZE);
Steve French07cc6cf2011-05-27 04:12:29 +0000578 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC ||
579 server->capabilities & CAP_EXTENDED_SECURITY) &&
580 (pSMBr->EncryptionKeyLength == 0)) {
Steve French254e55e2006-06-04 05:53:15 +0000581 /* decode security blob */
Jeff Layton820a8032011-05-04 08:05:26 -0400582 count = get_bcc(&pSMBr->hdr);
Jeff Laytone187e442007-10-16 17:10:44 +0000583 if (count < 16) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 rc = -EIO;
Jeff Laytone187e442007-10-16 17:10:44 +0000585 goto neg_err_exit;
586 }
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530587 spin_lock(&cifs_tcp_ses_lock);
Jeff Laytone7ddee92008-11-14 13:44:38 -0500588 if (server->srv_count > 1) {
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530589 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000590 if (memcmp(server->server_GUID,
591 pSMBr->u.extended_response.
592 GUID, 16) != 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000593 cFYI(1, "server UID changed");
Steve French254e55e2006-06-04 05:53:15 +0000594 memcpy(server->server_GUID,
Jeff Laytone187e442007-10-16 17:10:44 +0000595 pSMBr->u.extended_response.GUID,
596 16);
597 }
Jeff Laytone7ddee92008-11-14 13:44:38 -0500598 } else {
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530599 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000600 memcpy(server->server_GUID,
601 pSMBr->u.extended_response.GUID, 16);
Jeff Laytone7ddee92008-11-14 13:44:38 -0500602 }
Jeff Laytone187e442007-10-16 17:10:44 +0000603
604 if (count == 16) {
605 server->secType = RawNTLMSSP;
Steve French254e55e2006-06-04 05:53:15 +0000606 } else {
607 rc = decode_negTokenInit(pSMBr->u.extended_response.
Jeff Layton26efa0b2010-04-24 07:57:49 -0400608 SecurityBlob, count - 16,
609 server);
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000610 if (rc == 1)
Jeff Laytone5459372007-11-03 05:11:06 +0000611 rc = 0;
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000612 else
Steve French254e55e2006-06-04 05:53:15 +0000613 rc = -EINVAL;
Shirish Pargaonkar2b149f12010-09-18 22:02:18 -0500614 if (server->secType == Kerberos) {
615 if (!server->sec_kerberos &&
616 !server->sec_mskerberos)
617 rc = -EOPNOTSUPP;
618 } else if (server->secType == RawNTLMSSP) {
619 if (!server->sec_ntlmssp)
620 rc = -EOPNOTSUPP;
621 } else
622 rc = -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 }
Steve French96daf2b2011-05-27 04:34:02 +0000624 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
Steve French07cc6cf2011-05-27 04:12:29 +0000625 rc = -EIO; /* no crypt key only if plain text pwd */
626 goto neg_err_exit;
Steve French254e55e2006-06-04 05:53:15 +0000627 } else
628 server->capabilities &= ~CAP_EXTENDED_SECURITY;
629
Steve French6344a422006-06-12 04:18:35 +0000630#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French254e55e2006-06-04 05:53:15 +0000631signing_check:
Steve French6344a422006-06-12 04:18:35 +0000632#endif
Steve French762e5ab2007-06-28 18:41:42 +0000633 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
634 /* MUST_SIGN already includes the MAY_SIGN FLAG
635 so if this is zero it means that signing is disabled */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000636 cFYI(1, "Signing disabled");
Steve French96daf2b2011-05-27 04:34:02 +0000637 if (server->sec_mode & SECMODE_SIGN_REQUIRED) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000638 cERROR(1, "Server requires "
Jeff Layton7111d212007-10-16 16:50:25 +0000639 "packet signing to be enabled in "
Joe Perchesb6b38f72010-04-21 03:50:45 +0000640 "/proc/fs/cifs/SecurityFlags.");
Steve Frenchabb63d62007-10-18 02:58:40 +0000641 rc = -EOPNOTSUPP;
642 }
Steve French96daf2b2011-05-27 04:34:02 +0000643 server->sec_mode &=
Steve French254e55e2006-06-04 05:53:15 +0000644 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Steve French762e5ab2007-06-28 18:41:42 +0000645 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
646 /* signing required */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000647 cFYI(1, "Must sign - secFlags 0x%x", secFlags);
Steve French96daf2b2011-05-27 04:34:02 +0000648 if ((server->sec_mode &
Steve French762e5ab2007-06-28 18:41:42 +0000649 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000650 cERROR(1, "signing required but server lacks support");
Jeff38c10a12007-07-06 21:10:07 +0000651 rc = -EOPNOTSUPP;
Steve French762e5ab2007-06-28 18:41:42 +0000652 } else
Steve French96daf2b2011-05-27 04:34:02 +0000653 server->sec_mode |= SECMODE_SIGN_REQUIRED;
Steve French762e5ab2007-06-28 18:41:42 +0000654 } else {
655 /* signing optional ie CIFSSEC_MAY_SIGN */
Steve French96daf2b2011-05-27 04:34:02 +0000656 if ((server->sec_mode & SECMODE_SIGN_REQUIRED) == 0)
657 server->sec_mode &=
Steve French254e55e2006-06-04 05:53:15 +0000658 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 }
Steve French50c2f752007-07-13 00:33:32 +0000660
661neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700662 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000663
Joe Perchesb6b38f72010-04-21 03:50:45 +0000664 cFYI(1, "negprot rc %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 return rc;
666}
667
668int
Pavel Shilovsky2e6e02a2012-05-25 11:11:39 +0400669CIFSSMBTDis(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670{
671 struct smb_hdr *smb_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673
Joe Perchesb6b38f72010-04-21 03:50:45 +0000674 cFYI(1, "In tree disconnect");
Jeff Laytonf1987b42008-11-15 11:12:47 -0500675
676 /* BB: do we need to check this? These should never be NULL. */
677 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
678 return -EIO;
679
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 /*
Jeff Laytonf1987b42008-11-15 11:12:47 -0500681 * No need to return error on this operation if tid invalidated and
682 * closed on server already e.g. due to tcp session crashing. Also,
683 * the tcon is no longer on the list, so no need to take lock before
684 * checking this.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 */
Steve French268875b2009-06-25 00:29:21 +0000686 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
Steve French50c2f752007-07-13 00:33:32 +0000687 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688
Steve French50c2f752007-07-13 00:33:32 +0000689 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700690 (void **)&smb_buffer);
Jeff Laytonf1987b42008-11-15 11:12:47 -0500691 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 return rc;
Steve French133672e2007-11-13 22:41:37 +0000693
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400694 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)smb_buffer, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000696 cFYI(1, "Tree disconnect failed %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697
Steve French50c2f752007-07-13 00:33:32 +0000698 /* No need to return error on this operation if tid invalidated and
Jeff Laytonf1987b42008-11-15 11:12:47 -0500699 closed on server already e.g. due to tcp session crashing */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 if (rc == -EAGAIN)
701 rc = 0;
702
703 return rc;
704}
705
Jeff Layton766fdbb2011-01-11 07:24:21 -0500706/*
707 * This is a no-op for now. We're not really interested in the reply, but
708 * rather in the fact that the server sent one and that server->lstrp
709 * gets updated.
710 *
711 * FIXME: maybe we should consider checking that the reply matches request?
712 */
713static void
714cifs_echo_callback(struct mid_q_entry *mid)
715{
716 struct TCP_Server_Info *server = mid->callback_data;
717
718 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +0400719 add_credits(server, 1, CIFS_ECHO_OP);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500720}
721
722int
723CIFSSMBEcho(struct TCP_Server_Info *server)
724{
725 ECHO_REQ *smb;
726 int rc = 0;
Jeff Laytonfcc31cb2011-05-19 16:22:53 -0400727 struct kvec iov;
Jeff Layton766fdbb2011-01-11 07:24:21 -0500728
729 cFYI(1, "In echo request");
730
731 rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
732 if (rc)
733 return rc;
734
735 /* set up echo request */
Steve French5443d132011-03-13 05:08:25 +0000736 smb->hdr.Tid = 0xffff;
Jeff Layton99d86c8f2011-01-20 21:19:25 -0500737 smb->hdr.WordCount = 1;
738 put_unaligned_le16(1, &smb->EchoCount);
Jeff Layton820a8032011-05-04 08:05:26 -0400739 put_bcc(1, &smb->hdr);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500740 smb->Data[0] = 'a';
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000741 inc_rfc1001_len(smb, 3);
Jeff Laytonfcc31cb2011-05-19 16:22:53 -0400742 iov.iov_base = smb;
743 iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
Jeff Layton766fdbb2011-01-11 07:24:21 -0500744
Jeff Layton44d22d82011-10-19 15:29:49 -0400745 rc = cifs_call_async(server, &iov, 1, NULL, cifs_echo_callback,
Pavel Shilovskya891f0f2012-05-23 16:14:34 +0400746 server, CIFS_ASYNC_OP | CIFS_ECHO_OP);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500747 if (rc)
748 cFYI(1, "Echo request failed: %d", rc);
749
750 cifs_small_buf_release(smb);
751
752 return rc;
753}
754
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755int
Pavel Shilovsky58c45c52012-05-25 10:54:49 +0400756CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758 LOGOFF_ANDX_REQ *pSMB;
759 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760
Joe Perchesb6b38f72010-04-21 03:50:45 +0000761 cFYI(1, "In SMBLogoff for session disconnect");
Jeff Layton14fbf502008-11-14 13:53:46 -0500762
763 /*
764 * BB: do we need to check validity of ses and server? They should
765 * always be valid since we have an active reference. If not, that
766 * should probably be a BUG()
767 */
768 if (!ses || !ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769 return -EIO;
770
Steve Frenchd7b619c2010-02-25 05:36:46 +0000771 mutex_lock(&ses->session_mutex);
Steve French3b795212008-11-13 19:45:32 +0000772 if (ses->need_reconnect)
773 goto session_already_dead; /* no need to send SMBlogoff if uid
774 already closed due to reconnect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
776 if (rc) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000777 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 return rc;
779 }
780
Pavel Shilovsky88257362012-05-23 14:01:59 +0400781 pSMB->hdr.Mid = get_next_mid(ses->server);
Steve French1982c342005-08-17 12:38:22 -0700782
Steve French96daf2b2011-05-27 04:34:02 +0000783 if (ses->server->sec_mode &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
785 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786
787 pSMB->hdr.Uid = ses->Suid;
788
789 pSMB->AndXCommand = 0xFF;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400790 rc = SendReceiveNoRsp(xid, ses, (char *) pSMB, 0);
Steve French3b795212008-11-13 19:45:32 +0000791session_already_dead:
Steve Frenchd7b619c2010-02-25 05:36:46 +0000792 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793
794 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000795 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 error */
797 if (rc == -EAGAIN)
798 rc = 0;
799 return rc;
800}
801
802int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400803CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
804 const char *fileName, __u16 type,
805 const struct nls_table *nls_codepage, int remap)
Steve French2d785a52007-07-15 01:48:57 +0000806{
807 TRANSACTION2_SPI_REQ *pSMB = NULL;
808 TRANSACTION2_SPI_RSP *pSMBr = NULL;
809 struct unlink_psx_rq *pRqD;
810 int name_len;
811 int rc = 0;
812 int bytes_returned = 0;
813 __u16 params, param_offset, offset, byte_count;
814
Joe Perchesb6b38f72010-04-21 03:50:45 +0000815 cFYI(1, "In POSIX delete");
Steve French2d785a52007-07-15 01:48:57 +0000816PsxDelete:
817 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
818 (void **) &pSMBr);
819 if (rc)
820 return rc;
821
822 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
823 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -0600824 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
825 PATH_MAX, nls_codepage, remap);
Steve French2d785a52007-07-15 01:48:57 +0000826 name_len++; /* trailing null */
827 name_len *= 2;
828 } else { /* BB add path length overrun check */
829 name_len = strnlen(fileName, PATH_MAX);
830 name_len++; /* trailing null */
831 strncpy(pSMB->FileName, fileName, name_len);
832 }
833
834 params = 6 + name_len;
835 pSMB->MaxParameterCount = cpu_to_le16(2);
836 pSMB->MaxDataCount = 0; /* BB double check this with jra */
837 pSMB->MaxSetupCount = 0;
838 pSMB->Reserved = 0;
839 pSMB->Flags = 0;
840 pSMB->Timeout = 0;
841 pSMB->Reserved2 = 0;
842 param_offset = offsetof(struct smb_com_transaction2_spi_req,
843 InformationLevel) - 4;
844 offset = param_offset + params;
845
846 /* Setup pointer to Request Data (inode type) */
847 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
848 pRqD->type = cpu_to_le16(type);
849 pSMB->ParameterOffset = cpu_to_le16(param_offset);
850 pSMB->DataOffset = cpu_to_le16(offset);
851 pSMB->SetupCount = 1;
852 pSMB->Reserved3 = 0;
853 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
854 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
855
856 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
857 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
858 pSMB->ParameterCount = cpu_to_le16(params);
859 pSMB->TotalParameterCount = pSMB->ParameterCount;
860 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
861 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000862 inc_rfc1001_len(pSMB, byte_count);
Steve French2d785a52007-07-15 01:48:57 +0000863 pSMB->ByteCount = cpu_to_le16(byte_count);
864 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
865 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000866 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000867 cFYI(1, "Posix delete returned %d", rc);
Steve French2d785a52007-07-15 01:48:57 +0000868 cifs_buf_release(pSMB);
869
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400870 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve French2d785a52007-07-15 01:48:57 +0000871
872 if (rc == -EAGAIN)
873 goto PsxDelete;
874
875 return rc;
876}
877
878int
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700879CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
880 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881{
882 DELETE_FILE_REQ *pSMB = NULL;
883 DELETE_FILE_RSP *pSMBr = NULL;
884 int rc = 0;
885 int bytes_returned;
886 int name_len;
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700887 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888
889DelFileRetry:
890 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
891 (void **) &pSMBr);
892 if (rc)
893 return rc;
894
895 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700896 name_len = cifsConvertToUTF16((__le16 *) pSMB->fileName, name,
897 PATH_MAX, cifs_sb->local_nls,
898 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899 name_len++; /* trailing null */
900 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700901 } else { /* BB improve check for buffer overruns BB */
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700902 name_len = strnlen(name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 name_len++; /* trailing null */
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700904 strncpy(pSMB->fileName, name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 }
906 pSMB->SearchAttributes =
907 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
908 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000909 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 pSMB->ByteCount = cpu_to_le16(name_len + 1);
911 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
912 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400913 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000914 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000915 cFYI(1, "Error in RMFile = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916
917 cifs_buf_release(pSMB);
918 if (rc == -EAGAIN)
919 goto DelFileRetry;
920
921 return rc;
922}
923
924int
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400925CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
926 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927{
928 DELETE_DIRECTORY_REQ *pSMB = NULL;
929 DELETE_DIRECTORY_RSP *pSMBr = NULL;
930 int rc = 0;
931 int bytes_returned;
932 int name_len;
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400933 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934
Joe Perchesb6b38f72010-04-21 03:50:45 +0000935 cFYI(1, "In CIFSSMBRmDir");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936RmDirRetry:
937 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
938 (void **) &pSMBr);
939 if (rc)
940 return rc;
941
942 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400943 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
944 PATH_MAX, cifs_sb->local_nls,
945 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946 name_len++; /* trailing null */
947 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700948 } else { /* BB improve check for buffer overruns BB */
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400949 name_len = strnlen(name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950 name_len++; /* trailing null */
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400951 strncpy(pSMB->DirName, name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952 }
953
954 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000955 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956 pSMB->ByteCount = cpu_to_le16(name_len + 1);
957 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
958 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400959 cifs_stats_inc(&tcon->stats.cifs_stats.num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000960 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000961 cFYI(1, "Error in RMDir = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962
963 cifs_buf_release(pSMB);
964 if (rc == -EAGAIN)
965 goto RmDirRetry;
966 return rc;
967}
968
969int
Pavel Shilovskyf4367202012-03-17 11:41:12 +0300970CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
971 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972{
973 int rc = 0;
974 CREATE_DIRECTORY_REQ *pSMB = NULL;
975 CREATE_DIRECTORY_RSP *pSMBr = NULL;
976 int bytes_returned;
977 int name_len;
Pavel Shilovskyf4367202012-03-17 11:41:12 +0300978 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979
Joe Perchesb6b38f72010-04-21 03:50:45 +0000980 cFYI(1, "In CIFSSMBMkDir");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981MkDirRetry:
982 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
983 (void **) &pSMBr);
984 if (rc)
985 return rc;
986
987 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -0600988 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
Pavel Shilovskyf4367202012-03-17 11:41:12 +0300989 PATH_MAX, cifs_sb->local_nls,
990 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991 name_len++; /* trailing null */
992 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700993 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 name_len = strnlen(name, PATH_MAX);
995 name_len++; /* trailing null */
996 strncpy(pSMB->DirName, name, name_len);
997 }
998
999 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001000 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001 pSMB->ByteCount = cpu_to_le16(name_len + 1);
1002 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1003 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001004 cifs_stats_inc(&tcon->stats.cifs_stats.num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +00001005 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001006 cFYI(1, "Error in Mkdir = %d", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07001007
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 cifs_buf_release(pSMB);
1009 if (rc == -EAGAIN)
1010 goto MkDirRetry;
1011 return rc;
1012}
1013
Steve French2dd29d32007-04-23 22:07:35 +00001014int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001015CIFSPOSIXCreate(const unsigned int xid, struct cifs_tcon *tcon,
1016 __u32 posix_flags, __u64 mode, __u16 *netfid,
1017 FILE_UNIX_BASIC_INFO *pRetData, __u32 *pOplock,
1018 const char *name, const struct nls_table *nls_codepage,
1019 int remap)
Steve French2dd29d32007-04-23 22:07:35 +00001020{
1021 TRANSACTION2_SPI_REQ *pSMB = NULL;
1022 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1023 int name_len;
1024 int rc = 0;
1025 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001026 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +00001027 OPEN_PSX_REQ *pdata;
1028 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +00001029
Joe Perchesb6b38f72010-04-21 03:50:45 +00001030 cFYI(1, "In POSIX Create");
Steve French2dd29d32007-04-23 22:07:35 +00001031PsxCreat:
1032 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1033 (void **) &pSMBr);
1034 if (rc)
1035 return rc;
1036
1037 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1038 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001039 cifsConvertToUTF16((__le16 *) pSMB->FileName, name,
1040 PATH_MAX, nls_codepage, remap);
Steve French2dd29d32007-04-23 22:07:35 +00001041 name_len++; /* trailing null */
1042 name_len *= 2;
1043 } else { /* BB improve the check for buffer overruns BB */
1044 name_len = strnlen(name, PATH_MAX);
1045 name_len++; /* trailing null */
1046 strncpy(pSMB->FileName, name, name_len);
1047 }
1048
1049 params = 6 + name_len;
1050 count = sizeof(OPEN_PSX_REQ);
1051 pSMB->MaxParameterCount = cpu_to_le16(2);
1052 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1053 pSMB->MaxSetupCount = 0;
1054 pSMB->Reserved = 0;
1055 pSMB->Flags = 0;
1056 pSMB->Timeout = 0;
1057 pSMB->Reserved2 = 0;
1058 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001059 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001060 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001061 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001062 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001063 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001064 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001065 pdata->OpenFlags = cpu_to_le32(*pOplock);
1066 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1067 pSMB->DataOffset = cpu_to_le16(offset);
1068 pSMB->SetupCount = 1;
1069 pSMB->Reserved3 = 0;
1070 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1071 byte_count = 3 /* pad */ + params + count;
1072
1073 pSMB->DataCount = cpu_to_le16(count);
1074 pSMB->ParameterCount = cpu_to_le16(params);
1075 pSMB->TotalDataCount = pSMB->DataCount;
1076 pSMB->TotalParameterCount = pSMB->ParameterCount;
1077 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1078 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001079 inc_rfc1001_len(pSMB, byte_count);
Steve French2dd29d32007-04-23 22:07:35 +00001080 pSMB->ByteCount = cpu_to_le16(byte_count);
1081 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1082 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1083 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001084 cFYI(1, "Posix create returned %d", rc);
Steve French2dd29d32007-04-23 22:07:35 +00001085 goto psx_create_err;
1086 }
1087
Joe Perchesb6b38f72010-04-21 03:50:45 +00001088 cFYI(1, "copying inode info");
Steve French2dd29d32007-04-23 22:07:35 +00001089 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1090
Jeff Layton820a8032011-05-04 08:05:26 -04001091 if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) {
Steve French2dd29d32007-04-23 22:07:35 +00001092 rc = -EIO; /* bad smb */
1093 goto psx_create_err;
1094 }
1095
1096 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001097 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001098 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001099
Steve French2dd29d32007-04-23 22:07:35 +00001100 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001101 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001102 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1103 /* Let caller know file was created so we can set the mode. */
1104 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001105 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001106 *pOplock |= CIFS_CREATE_ACTION;
1107 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001108 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1109 pRetData->Type = cpu_to_le32(-1); /* unknown */
Joe Perchesb6b38f72010-04-21 03:50:45 +00001110 cFYI(DBG2, "unknown type");
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001111 } else {
Jeff Layton820a8032011-05-04 08:05:26 -04001112 if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001113 + sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001114 cERROR(1, "Open response data too small");
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001115 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001116 goto psx_create_err;
1117 }
Steve French50c2f752007-07-13 00:33:32 +00001118 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001119 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001120 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001121 }
Steve French2dd29d32007-04-23 22:07:35 +00001122
1123psx_create_err:
1124 cifs_buf_release(pSMB);
1125
Steve French65bc98b2009-07-10 15:27:25 +00001126 if (posix_flags & SMB_O_DIRECTORY)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001127 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixmkdirs);
Steve French65bc98b2009-07-10 15:27:25 +00001128 else
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001129 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixopens);
Steve French2dd29d32007-04-23 22:07:35 +00001130
1131 if (rc == -EAGAIN)
1132 goto PsxCreat;
1133
Steve French50c2f752007-07-13 00:33:32 +00001134 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001135}
1136
Steve Frencha9d02ad2005-08-24 23:06:05 -07001137static __u16 convert_disposition(int disposition)
1138{
1139 __u16 ofun = 0;
1140
1141 switch (disposition) {
1142 case FILE_SUPERSEDE:
1143 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1144 break;
1145 case FILE_OPEN:
1146 ofun = SMBOPEN_OAPPEND;
1147 break;
1148 case FILE_CREATE:
1149 ofun = SMBOPEN_OCREATE;
1150 break;
1151 case FILE_OPEN_IF:
1152 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1153 break;
1154 case FILE_OVERWRITE:
1155 ofun = SMBOPEN_OTRUNC;
1156 break;
1157 case FILE_OVERWRITE_IF:
1158 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1159 break;
1160 default:
Joe Perchesb6b38f72010-04-21 03:50:45 +00001161 cFYI(1, "unknown disposition %d", disposition);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001162 ofun = SMBOPEN_OAPPEND; /* regular open */
1163 }
1164 return ofun;
1165}
1166
Jeff Layton35fc37d2008-05-14 10:22:03 -07001167static int
1168access_flags_to_smbopen_mode(const int access_flags)
1169{
1170 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1171
1172 if (masked_flags == GENERIC_READ)
1173 return SMBOPEN_READ;
1174 else if (masked_flags == GENERIC_WRITE)
1175 return SMBOPEN_WRITE;
1176
1177 /* just go for read/write */
1178 return SMBOPEN_READWRITE;
1179}
1180
Steve Frencha9d02ad2005-08-24 23:06:05 -07001181int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001182SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001183 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001184 const int access_flags, const int create_options, __u16 *netfid,
1185 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001186 const struct nls_table *nls_codepage, int remap)
1187{
1188 int rc = -EACCES;
1189 OPENX_REQ *pSMB = NULL;
1190 OPENX_RSP *pSMBr = NULL;
1191 int bytes_returned;
1192 int name_len;
1193 __u16 count;
1194
1195OldOpenRetry:
1196 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1197 (void **) &pSMBr);
1198 if (rc)
1199 return rc;
1200
1201 pSMB->AndXCommand = 0xFF; /* none */
1202
1203 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1204 count = 1; /* account for one byte pad to word boundary */
1205 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001206 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1207 fileName, PATH_MAX, nls_codepage, remap);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001208 name_len++; /* trailing null */
1209 name_len *= 2;
1210 } else { /* BB improve check for buffer overruns BB */
1211 count = 0; /* no pad */
1212 name_len = strnlen(fileName, PATH_MAX);
1213 name_len++; /* trailing null */
1214 strncpy(pSMB->fileName, fileName, name_len);
1215 }
1216 if (*pOplock & REQ_OPLOCK)
1217 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001218 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001219 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001220
Steve Frencha9d02ad2005-08-24 23:06:05 -07001221 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001222 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001223 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1224 /* set file as system file if special file such
1225 as fifo and server expecting SFU style and
1226 no Unix extensions */
1227
Steve French790fe572007-07-07 19:25:05 +00001228 if (create_options & CREATE_OPTION_SPECIAL)
1229 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001230 else /* BB FIXME BB */
1231 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001232
Jeff Layton67750fb2008-05-09 22:28:02 +00001233 if (create_options & CREATE_OPTION_READONLY)
1234 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001235
1236 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001237/* pSMB->CreateOptions = cpu_to_le32(create_options &
1238 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001239 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001240
1241 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001242 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001243 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001244 inc_rfc1001_len(pSMB, count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001245
1246 pSMB->ByteCount = cpu_to_le16(count);
1247 /* long_op set to 1 to allow for oplock break timeouts */
1248 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001249 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001250 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001251 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001252 cFYI(1, "Error in Open = %d", rc);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001253 } else {
1254 /* BB verify if wct == 15 */
1255
Steve French582d21e2008-05-13 04:54:12 +00001256/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001257
1258 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1259 /* Let caller know file was created so we can set the mode. */
1260 /* Do we care about the CreateAction in any other cases? */
1261 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001262/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001263 *pOplock |= CIFS_CREATE_ACTION; */
1264 /* BB FIXME END */
1265
Steve French790fe572007-07-07 19:25:05 +00001266 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001267 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1268 pfile_info->LastAccessTime = 0; /* BB fixme */
1269 pfile_info->LastWriteTime = 0; /* BB fixme */
1270 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001271 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001272 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001273 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001274 pfile_info->AllocationSize =
1275 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1276 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001277 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001278 pfile_info->DeletePending = 0;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001279 }
1280 }
1281
1282 cifs_buf_release(pSMB);
1283 if (rc == -EAGAIN)
1284 goto OldOpenRetry;
1285 return rc;
1286}
1287
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001289CIFSSMBOpen(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001291 const int access_flags, const int create_options, __u16 *netfid,
1292 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001293 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294{
1295 int rc = -EACCES;
1296 OPEN_REQ *pSMB = NULL;
1297 OPEN_RSP *pSMBr = NULL;
1298 int bytes_returned;
1299 int name_len;
1300 __u16 count;
1301
1302openRetry:
1303 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1304 (void **) &pSMBr);
1305 if (rc)
1306 return rc;
1307
1308 pSMB->AndXCommand = 0xFF; /* none */
1309
1310 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1311 count = 1; /* account for one byte pad to word boundary */
1312 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001313 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1314 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315 name_len++; /* trailing null */
1316 name_len *= 2;
1317 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001318 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319 count = 0; /* no pad */
1320 name_len = strnlen(fileName, PATH_MAX);
1321 name_len++; /* trailing null */
1322 pSMB->NameLength = cpu_to_le16(name_len);
1323 strncpy(pSMB->fileName, fileName, name_len);
1324 }
1325 if (*pOplock & REQ_OPLOCK)
1326 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001327 else if (*pOplock & REQ_BATCHOPLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1330 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -07001331 /* set file as system file if special file such
1332 as fifo and server expecting SFU style and
1333 no Unix extensions */
Steve French790fe572007-07-07 19:25:05 +00001334 if (create_options & CREATE_OPTION_SPECIAL)
Steve Frencheda3c0292005-07-21 15:20:28 -07001335 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1336 else
1337 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Jeff Layton67750fb2008-05-09 22:28:02 +00001338
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339 /* XP does not handle ATTR_POSIX_SEMANTICS */
1340 /* but it helps speed up case sensitive checks for other
1341 servers such as Samba */
1342 if (tcon->ses->capabilities & CAP_UNIX)
1343 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1344
Jeff Layton67750fb2008-05-09 22:28:02 +00001345 if (create_options & CREATE_OPTION_READONLY)
1346 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1347
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1349 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -07001350 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001351 /* BB Expirement with various impersonation levels and verify */
1352 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353 pSMB->SecurityFlags =
1354 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1355
1356 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001357 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358
1359 pSMB->ByteCount = cpu_to_le16(count);
1360 /* long_op set to 1 to allow for oplock break timeouts */
1361 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001362 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001363 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001364 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001365 cFYI(1, "Error in Open = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366 } else {
Steve French09d1db52005-04-28 22:41:08 -07001367 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1369 /* Let caller know file was created so we can set the mode. */
1370 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001371 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve French50c2f752007-07-13 00:33:32 +00001372 *pOplock |= CIFS_CREATE_ACTION;
Steve French790fe572007-07-07 19:25:05 +00001373 if (pfile_info) {
Steve French61e74802008-12-03 00:57:54 +00001374 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1375 36 /* CreationTime to Attributes */);
1376 /* the file_info buf is endian converted by caller */
1377 pfile_info->AllocationSize = pSMBr->AllocationSize;
1378 pfile_info->EndOfFile = pSMBr->EndOfFile;
1379 pfile_info->NumberOfLinks = cpu_to_le32(1);
1380 pfile_info->DeletePending = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001383
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384 cifs_buf_release(pSMB);
1385 if (rc == -EAGAIN)
1386 goto openRetry;
1387 return rc;
1388}
1389
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001390/*
1391 * Discard any remaining data in the current SMB. To do this, we borrow the
1392 * current bigbuf.
1393 */
1394static int
1395cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1396{
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001397 unsigned int rfclen = get_rfc1002_length(server->smallbuf);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001398 int remaining = rfclen + 4 - server->total_read;
1399 struct cifs_readdata *rdata = mid->callback_data;
1400
1401 while (remaining > 0) {
1402 int length;
1403
1404 length = cifs_read_from_socket(server, server->bigbuf,
1405 min_t(unsigned int, remaining,
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001406 CIFSMaxBufSize + MAX_HEADER_SIZE(server)));
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001407 if (length < 0)
1408 return length;
1409 server->total_read += length;
1410 remaining -= length;
1411 }
1412
1413 dequeue_mid(mid, rdata->result);
1414 return 0;
1415}
1416
Pavel Shilovsky09a47072012-09-18 16:20:29 -07001417int
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001418cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1419{
1420 int length, len;
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001421 unsigned int data_offset, data_len;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001422 struct cifs_readdata *rdata = mid->callback_data;
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001423 char *buf = server->smallbuf;
1424 unsigned int buflen = get_rfc1002_length(buf) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001425
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001426 cFYI(1, "%s: mid=%llu offset=%llu bytes=%u", __func__,
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001427 mid->mid, rdata->offset, rdata->bytes);
1428
1429 /*
1430 * read the rest of READ_RSP header (sans Data array), or whatever we
1431 * can if there's not enough data. At this point, we've read down to
1432 * the Mid.
1433 */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001434 len = min_t(unsigned int, buflen, server->vals->read_rsp_size) -
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001435 HEADER_SIZE(server) + 1;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001436
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001437 rdata->iov[0].iov_base = buf + HEADER_SIZE(server) - 1;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001438 rdata->iov[0].iov_len = len;
1439
1440 length = cifs_readv_from_socket(server, rdata->iov, 1, len);
1441 if (length < 0)
1442 return length;
1443 server->total_read += length;
1444
1445 /* Was the SMB read successful? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001446 rdata->result = server->ops->map_error(buf, false);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001447 if (rdata->result != 0) {
1448 cFYI(1, "%s: server returned error %d", __func__,
1449 rdata->result);
1450 return cifs_readv_discard(server, mid);
1451 }
1452
1453 /* Is there enough to get to the rest of the READ_RSP header? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001454 if (server->total_read < server->vals->read_rsp_size) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001455 cFYI(1, "%s: server returned short header. got=%u expected=%zu",
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001456 __func__, server->total_read,
1457 server->vals->read_rsp_size);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001458 rdata->result = -EIO;
1459 return cifs_readv_discard(server, mid);
1460 }
1461
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001462 data_offset = server->ops->read_data_offset(buf) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001463 if (data_offset < server->total_read) {
1464 /*
1465 * win2k8 sometimes sends an offset of 0 when the read
1466 * is beyond the EOF. Treat it as if the data starts just after
1467 * the header.
1468 */
1469 cFYI(1, "%s: data offset (%u) inside read response header",
1470 __func__, data_offset);
1471 data_offset = server->total_read;
1472 } else if (data_offset > MAX_CIFS_SMALL_BUFFER_SIZE) {
1473 /* data_offset is beyond the end of smallbuf */
1474 cFYI(1, "%s: data offset (%u) beyond end of smallbuf",
1475 __func__, data_offset);
1476 rdata->result = -EIO;
1477 return cifs_readv_discard(server, mid);
1478 }
1479
1480 cFYI(1, "%s: total_read=%u data_offset=%u", __func__,
1481 server->total_read, data_offset);
1482
1483 len = data_offset - server->total_read;
1484 if (len > 0) {
1485 /* read any junk before data into the rest of smallbuf */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001486 rdata->iov[0].iov_base = buf + server->total_read;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001487 rdata->iov[0].iov_len = len;
1488 length = cifs_readv_from_socket(server, rdata->iov, 1, len);
1489 if (length < 0)
1490 return length;
1491 server->total_read += length;
1492 }
1493
1494 /* set up first iov for signature check */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001495 rdata->iov[0].iov_base = buf;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001496 rdata->iov[0].iov_len = server->total_read;
1497 cFYI(1, "0: iov_base=%p iov_len=%zu",
1498 rdata->iov[0].iov_base, rdata->iov[0].iov_len);
1499
1500 /* how much data is in the response? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001501 data_len = server->ops->read_data_length(buf);
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001502 if (data_offset + data_len > buflen) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001503 /* data_len is corrupt -- discard frame */
1504 rdata->result = -EIO;
1505 return cifs_readv_discard(server, mid);
1506 }
1507
1508 /* marshal up the page array */
Jeff Layton3cf003c2012-07-11 09:09:36 -04001509 cifs_kmap_lock();
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001510 len = rdata->marshal_iov(rdata, data_len);
Jeff Layton3cf003c2012-07-11 09:09:36 -04001511 cifs_kmap_unlock();
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001512 data_len -= len;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001513
1514 /* issue the read if we have any iovecs left to fill */
1515 if (rdata->nr_iov > 1) {
1516 length = cifs_readv_from_socket(server, &rdata->iov[1],
1517 rdata->nr_iov - 1, len);
1518 if (length < 0)
1519 return length;
1520 server->total_read += length;
1521 } else {
1522 length = 0;
1523 }
1524
1525 rdata->bytes = length;
1526
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001527 cFYI(1, "total_read=%u buflen=%u remaining=%u", server->total_read,
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001528 buflen, data_len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001529
1530 /* discard anything left over */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001531 if (server->total_read < buflen)
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001532 return cifs_readv_discard(server, mid);
1533
1534 dequeue_mid(mid, false);
1535 return length;
1536}
1537
1538static void
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001539cifs_readv_callback(struct mid_q_entry *mid)
1540{
1541 struct cifs_readdata *rdata = mid->callback_data;
1542 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1543 struct TCP_Server_Info *server = tcon->ses->server;
1544
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001545 cFYI(1, "%s: mid=%llu state=%d result=%d bytes=%u", __func__,
1546 mid->mid, mid->mid_state, rdata->result, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001547
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001548 switch (mid->mid_state) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001549 case MID_RESPONSE_RECEIVED:
1550 /* result already set, check signature */
1551 if (server->sec_mode &
1552 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
Steve French985e4ff02012-08-03 09:42:45 -05001553 int rc = 0;
1554
1555 rc = cifs_verify_signature(rdata->iov, rdata->nr_iov,
1556 server,
1557 mid->sequence_number + 1);
1558 if (rc)
1559 cERROR(1, "SMB signature verification returned "
1560 "error = %d", rc);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001561 }
1562 /* FIXME: should this be counted toward the initiating task? */
1563 task_io_account_read(rdata->bytes);
1564 cifs_stats_bytes_read(tcon, rdata->bytes);
1565 break;
1566 case MID_REQUEST_SUBMITTED:
1567 case MID_RETRY_NEEDED:
1568 rdata->result = -EAGAIN;
1569 break;
1570 default:
1571 rdata->result = -EIO;
1572 }
1573
Jeff Laytonda472fc2012-03-23 14:40:53 -04001574 queue_work(cifsiod_wq, &rdata->work);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001575 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04001576 add_credits(server, 1, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001577}
1578
1579/* cifs_async_readv - send an async write, and set up mid to handle result */
1580int
1581cifs_async_readv(struct cifs_readdata *rdata)
1582{
1583 int rc;
1584 READ_REQ *smb = NULL;
1585 int wct;
1586 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1587
1588 cFYI(1, "%s: offset=%llu bytes=%u", __func__,
1589 rdata->offset, rdata->bytes);
1590
1591 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1592 wct = 12;
1593 else {
1594 wct = 10; /* old style read */
1595 if ((rdata->offset >> 32) > 0) {
1596 /* can not handle this big offset for old */
1597 return -EIO;
1598 }
1599 }
1600
1601 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **)&smb);
1602 if (rc)
1603 return rc;
1604
1605 smb->hdr.Pid = cpu_to_le16((__u16)rdata->pid);
1606 smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16));
1607
1608 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07001609 smb->Fid = rdata->cfile->fid.netfid;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001610 smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF);
1611 if (wct == 12)
1612 smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32);
1613 smb->Remaining = 0;
1614 smb->MaxCount = cpu_to_le16(rdata->bytes & 0xFFFF);
1615 smb->MaxCountHigh = cpu_to_le32(rdata->bytes >> 16);
1616 if (wct == 12)
1617 smb->ByteCount = 0;
1618 else {
1619 /* old style read */
1620 struct smb_com_readx_req *smbr =
1621 (struct smb_com_readx_req *)smb;
1622 smbr->ByteCount = 0;
1623 }
1624
1625 /* 4 for RFC1001 length + 1 for BCC */
1626 rdata->iov[0].iov_base = smb;
1627 rdata->iov[0].iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
1628
Jeff Layton6993f742012-05-16 07:13:17 -04001629 kref_get(&rdata->refcount);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001630 rc = cifs_call_async(tcon->ses->server, rdata->iov, 1,
1631 cifs_readv_receive, cifs_readv_callback,
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04001632 rdata, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001633
1634 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001635 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Jeff Layton6993f742012-05-16 07:13:17 -04001636 else
1637 kref_put(&rdata->refcount, cifs_readdata_release);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001638
1639 cifs_small_buf_release(smb);
1640 return rc;
1641}
1642
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001644CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
1645 unsigned int *nbytes, char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646{
1647 int rc = -EACCES;
1648 READ_REQ *pSMB = NULL;
1649 READ_RSP *pSMBr = NULL;
1650 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001651 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001652 int resp_buf_type = 0;
1653 struct kvec iov[1];
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001654 __u32 pid = io_parms->pid;
1655 __u16 netfid = io_parms->netfid;
1656 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001657 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001658 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001659
Joe Perchesb6b38f72010-04-21 03:50:45 +00001660 cFYI(1, "Reading %d bytes on fid %d", count, netfid);
Steve French790fe572007-07-07 19:25:05 +00001661 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001662 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001663 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001664 wct = 10; /* old style read */
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001665 if ((offset >> 32) > 0) {
Steve French4c3130e2008-12-09 00:28:16 +00001666 /* can not handle this big offset for old */
1667 return -EIO;
1668 }
1669 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670
1671 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001672 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673 if (rc)
1674 return rc;
1675
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001676 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1677 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1678
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679 /* tcon and ses pointer are checked in smb_init */
1680 if (tcon->ses->server == NULL)
1681 return -ECONNABORTED;
1682
Steve Frenchec637e32005-12-12 20:53:18 -08001683 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684 pSMB->Fid = netfid;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001685 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001686 if (wct == 12)
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001687 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001688
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689 pSMB->Remaining = 0;
1690 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1691 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001692 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001693 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1694 else {
1695 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001696 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001697 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001698 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001699 }
Steve Frenchec637e32005-12-12 20:53:18 -08001700
1701 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001702 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve Frencha761ac52007-10-18 21:45:27 +00001703 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Jeff Layton77499812011-01-11 07:24:23 -05001704 &resp_buf_type, CIFS_LOG_ERROR);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001705 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001706 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001708 cERROR(1, "Send error in read = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709 } else {
1710 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1711 data_length = data_length << 16;
1712 data_length += le16_to_cpu(pSMBr->DataLength);
1713 *nbytes = data_length;
1714
1715 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001716 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717 || (data_length > count)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001718 cFYI(1, "bad length %d for count %d",
1719 data_length, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720 rc = -EIO;
1721 *nbytes = 0;
1722 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001723 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001724 le16_to_cpu(pSMBr->DataOffset);
1725/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001726 cERROR(1, "Faulting on read rc = %d",rc);
Steve French50c2f752007-07-13 00:33:32 +00001727 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001728 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001729 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001730 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731 }
1732 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733
Steve French4b8f9302006-02-26 16:41:18 +00001734/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001735 if (*buf) {
1736 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001737 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001738 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001739 cifs_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001740 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001741 /* return buffer to caller to free */
1742 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001743 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001744 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001745 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001746 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001747 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001748
1749 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750 since file handle passed in no longer valid */
1751 return rc;
1752}
1753
Steve Frenchec637e32005-12-12 20:53:18 -08001754
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001756CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001757 unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001758 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759{
1760 int rc = -EACCES;
1761 WRITE_REQ *pSMB = NULL;
1762 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001763 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001764 __u32 bytes_sent;
1765 __u16 byte_count;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001766 __u32 pid = io_parms->pid;
1767 __u16 netfid = io_parms->netfid;
1768 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001769 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001770 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771
Steve Frencha24e2d72010-04-03 17:20:21 +00001772 *nbytes = 0;
1773
Joe Perchesb6b38f72010-04-21 03:50:45 +00001774 /* cFYI(1, "write at %lld %d bytes", offset, count);*/
Steve French790fe572007-07-07 19:25:05 +00001775 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001776 return -ECONNABORTED;
1777
Steve French790fe572007-07-07 19:25:05 +00001778 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001779 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001780 else {
Steve French1c955182005-08-30 20:58:07 -07001781 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001782 if ((offset >> 32) > 0) {
1783 /* can not handle big offset for old srv */
1784 return -EIO;
1785 }
1786 }
Steve French1c955182005-08-30 20:58:07 -07001787
1788 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001789 (void **) &pSMBr);
1790 if (rc)
1791 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001792
1793 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1794 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1795
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796 /* tcon and ses pointer are checked in smb_init */
1797 if (tcon->ses->server == NULL)
1798 return -ECONNABORTED;
1799
1800 pSMB->AndXCommand = 0xFF; /* none */
1801 pSMB->Fid = netfid;
1802 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001803 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001804 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001805
Linus Torvalds1da177e2005-04-16 15:20:36 -07001806 pSMB->Reserved = 0xFFFFFFFF;
1807 pSMB->WriteMode = 0;
1808 pSMB->Remaining = 0;
1809
Steve French50c2f752007-07-13 00:33:32 +00001810 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811 can send more if LARGE_WRITE_X capability returned by the server and if
1812 our buffer is big enough or if we convert to iovecs on socket writes
1813 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001814 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1816 } else {
1817 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1818 & ~0xFF;
1819 }
1820
1821 if (bytes_sent > count)
1822 bytes_sent = count;
1823 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001824 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001825 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001826 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001827 else if (ubuf) {
1828 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001829 cifs_buf_release(pSMB);
1830 return -EFAULT;
1831 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001832 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001833 /* No buffer */
1834 cifs_buf_release(pSMB);
1835 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001836 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001837 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001838 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001839 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001840 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001841
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1843 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001844 inc_rfc1001_len(pSMB, byte_count);
Steve French1c955182005-08-30 20:58:07 -07001845
Steve French790fe572007-07-07 19:25:05 +00001846 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001847 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001848 else { /* old style write has byte count 4 bytes earlier
1849 so 4 bytes pad */
1850 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001851 (struct smb_com_writex_req *)pSMB;
1852 pSMBW->ByteCount = cpu_to_le16(byte_count);
1853 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854
1855 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1856 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001857 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00001859 cFYI(1, "Send error in write = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860 } else {
1861 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1862 *nbytes = (*nbytes) << 16;
1863 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301864
1865 /*
1866 * Mask off high 16 bits when bytes written as returned by the
1867 * server is greater than bytes requested by the client. Some
1868 * OS/2 servers are known to set incorrect CountHigh values.
1869 */
1870 if (*nbytes > count)
1871 *nbytes &= 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872 }
1873
1874 cifs_buf_release(pSMB);
1875
Steve French50c2f752007-07-13 00:33:32 +00001876 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001877 since file handle passed in no longer valid */
1878
1879 return rc;
1880}
1881
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001882void
1883cifs_writedata_release(struct kref *refcount)
1884{
1885 struct cifs_writedata *wdata = container_of(refcount,
1886 struct cifs_writedata, refcount);
1887
1888 if (wdata->cfile)
1889 cifsFileInfo_put(wdata->cfile);
1890
1891 kfree(wdata);
1892}
1893
1894/*
1895 * Write failed with a retryable error. Resend the write request. It's also
1896 * possible that the page was redirtied so re-clean the page.
1897 */
1898static void
1899cifs_writev_requeue(struct cifs_writedata *wdata)
1900{
1901 int i, rc;
1902 struct inode *inode = wdata->cfile->dentry->d_inode;
Pavel Shilovskyc9de5c82012-09-18 16:20:29 -07001903 struct TCP_Server_Info *server;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001904
1905 for (i = 0; i < wdata->nr_pages; i++) {
1906 lock_page(wdata->pages[i]);
1907 clear_page_dirty_for_io(wdata->pages[i]);
1908 }
1909
1910 do {
Pavel Shilovskyc9de5c82012-09-18 16:20:29 -07001911 server = tlink_tcon(wdata->cfile->tlink)->ses->server;
1912 rc = server->ops->async_writev(wdata);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001913 } while (rc == -EAGAIN);
1914
1915 for (i = 0; i < wdata->nr_pages; i++) {
1916 if (rc != 0)
1917 SetPageError(wdata->pages[i]);
1918 unlock_page(wdata->pages[i]);
1919 }
1920
1921 mapping_set_error(inode->i_mapping, rc);
1922 kref_put(&wdata->refcount, cifs_writedata_release);
1923}
1924
Jeff Laytonc2e87642012-03-23 14:40:55 -04001925void
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001926cifs_writev_complete(struct work_struct *work)
1927{
1928 struct cifs_writedata *wdata = container_of(work,
1929 struct cifs_writedata, work);
1930 struct inode *inode = wdata->cfile->dentry->d_inode;
1931 int i = 0;
1932
1933 if (wdata->result == 0) {
Jeff Layton597b0272012-03-23 14:40:56 -04001934 spin_lock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001935 cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
Jeff Layton597b0272012-03-23 14:40:56 -04001936 spin_unlock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001937 cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
1938 wdata->bytes);
1939 } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
1940 return cifs_writev_requeue(wdata);
1941
1942 for (i = 0; i < wdata->nr_pages; i++) {
1943 struct page *page = wdata->pages[i];
1944 if (wdata->result == -EAGAIN)
1945 __set_page_dirty_nobuffers(page);
1946 else if (wdata->result < 0)
1947 SetPageError(page);
1948 end_page_writeback(page);
1949 page_cache_release(page);
1950 }
1951 if (wdata->result != -EAGAIN)
1952 mapping_set_error(inode->i_mapping, wdata->result);
1953 kref_put(&wdata->refcount, cifs_writedata_release);
1954}
1955
1956struct cifs_writedata *
Jeff Laytonc2e87642012-03-23 14:40:55 -04001957cifs_writedata_alloc(unsigned int nr_pages, work_func_t complete)
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001958{
1959 struct cifs_writedata *wdata;
1960
1961 /* this would overflow */
1962 if (nr_pages == 0) {
1963 cERROR(1, "%s: called with nr_pages == 0!", __func__);
1964 return NULL;
1965 }
1966
1967 /* writedata + number of page pointers */
1968 wdata = kzalloc(sizeof(*wdata) +
1969 sizeof(struct page *) * (nr_pages - 1), GFP_NOFS);
1970 if (wdata != NULL) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001971 kref_init(&wdata->refcount);
Jeff Laytonda82f7e2012-03-23 14:40:56 -04001972 INIT_LIST_HEAD(&wdata->list);
1973 init_completion(&wdata->done);
1974 INIT_WORK(&wdata->work, complete);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001975 }
1976 return wdata;
1977}
1978
1979/*
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001980 * Check the mid_state and signature on received buffer (if any), and queue the
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001981 * workqueue completion task.
1982 */
1983static void
1984cifs_writev_callback(struct mid_q_entry *mid)
1985{
1986 struct cifs_writedata *wdata = mid->callback_data;
Steve French96daf2b2011-05-27 04:34:02 +00001987 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001988 unsigned int written;
1989 WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
1990
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001991 switch (mid->mid_state) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001992 case MID_RESPONSE_RECEIVED:
1993 wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
1994 if (wdata->result != 0)
1995 break;
1996
1997 written = le16_to_cpu(smb->CountHigh);
1998 written <<= 16;
1999 written += le16_to_cpu(smb->Count);
2000 /*
2001 * Mask off high 16 bits when bytes written as returned
2002 * by the server is greater than bytes requested by the
2003 * client. OS/2 servers are known to set incorrect
2004 * CountHigh values.
2005 */
2006 if (written > wdata->bytes)
2007 written &= 0xFFFF;
2008
2009 if (written < wdata->bytes)
2010 wdata->result = -ENOSPC;
2011 else
2012 wdata->bytes = written;
2013 break;
2014 case MID_REQUEST_SUBMITTED:
2015 case MID_RETRY_NEEDED:
2016 wdata->result = -EAGAIN;
2017 break;
2018 default:
2019 wdata->result = -EIO;
2020 break;
2021 }
2022
Jeff Laytonda472fc2012-03-23 14:40:53 -04002023 queue_work(cifsiod_wq, &wdata->work);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002024 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002025 add_credits(tcon->ses->server, 1, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002026}
2027
2028/* cifs_async_writev - send an async write, and set up mid to handle result */
2029int
2030cifs_async_writev(struct cifs_writedata *wdata)
2031{
2032 int i, rc = -EACCES;
2033 WRITE_REQ *smb = NULL;
2034 int wct;
Steve French96daf2b2011-05-27 04:34:02 +00002035 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002036 struct kvec *iov = NULL;
2037
2038 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
2039 wct = 14;
2040 } else {
2041 wct = 12;
2042 if (wdata->offset >> 32 > 0) {
2043 /* can not handle big offset for old srv */
2044 return -EIO;
2045 }
2046 }
2047
2048 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
2049 if (rc)
2050 goto async_writev_out;
2051
2052 /* 1 iov per page + 1 for header */
2053 iov = kzalloc((wdata->nr_pages + 1) * sizeof(*iov), GFP_NOFS);
2054 if (iov == NULL) {
2055 rc = -ENOMEM;
2056 goto async_writev_out;
2057 }
2058
Jeff Laytonfe5f5d22012-03-23 14:40:55 -04002059 smb->hdr.Pid = cpu_to_le16((__u16)wdata->pid);
2060 smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16));
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002061
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002062 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07002063 smb->Fid = wdata->cfile->fid.netfid;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002064 smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
2065 if (wct == 14)
2066 smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
2067 smb->Reserved = 0xFFFFFFFF;
2068 smb->WriteMode = 0;
2069 smb->Remaining = 0;
2070
2071 smb->DataOffset =
2072 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
2073
2074 /* 4 for RFC1001 length + 1 for BCC */
2075 iov[0].iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4 + 1;
2076 iov[0].iov_base = smb;
2077
Jeff Laytone9492872012-03-23 14:40:56 -04002078 /*
2079 * This function should marshal up the page array into the kvec
2080 * array, reserving [0] for the header. It should kmap the pages
2081 * and set the iov_len properly for each one. It may also set
2082 * wdata->bytes too.
2083 */
Jeff Layton3cf003c2012-07-11 09:09:36 -04002084 cifs_kmap_lock();
Jeff Laytone9492872012-03-23 14:40:56 -04002085 wdata->marshal_iov(iov, wdata);
Jeff Layton3cf003c2012-07-11 09:09:36 -04002086 cifs_kmap_unlock();
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002087
2088 cFYI(1, "async write at %llu %u bytes", wdata->offset, wdata->bytes);
2089
2090 smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
2091 smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16);
2092
2093 if (wct == 14) {
2094 inc_rfc1001_len(&smb->hdr, wdata->bytes + 1);
2095 put_bcc(wdata->bytes + 1, &smb->hdr);
2096 } else {
2097 /* wct == 12 */
2098 struct smb_com_writex_req *smbw =
2099 (struct smb_com_writex_req *)smb;
2100 inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
2101 put_bcc(wdata->bytes + 5, &smbw->hdr);
2102 iov[0].iov_len += 4; /* pad bigger by four bytes */
2103 }
2104
2105 kref_get(&wdata->refcount);
2106 rc = cifs_call_async(tcon->ses->server, iov, wdata->nr_pages + 1,
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002107 NULL, cifs_writev_callback, wdata, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002108
2109 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002110 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002111 else
2112 kref_put(&wdata->refcount, cifs_writedata_release);
2113
2114 /* send is done, unmap pages */
2115 for (i = 0; i < wdata->nr_pages; i++)
2116 kunmap(wdata->pages[i]);
2117
2118async_writev_out:
2119 cifs_small_buf_release(smb);
2120 kfree(iov);
2121 return rc;
2122}
2123
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002124int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002125CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
Pavel Shilovskyba9ad7252012-09-18 16:20:30 -07002126 unsigned int *nbytes, struct kvec *iov, int n_vec)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002127{
2128 int rc = -EACCES;
2129 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08002130 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002131 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08002132 int resp_buf_type = 0;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002133 __u32 pid = io_parms->pid;
2134 __u16 netfid = io_parms->netfid;
2135 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00002136 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002137 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002138
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04002139 *nbytes = 0;
2140
Joe Perchesb6b38f72010-04-21 03:50:45 +00002141 cFYI(1, "write2 at %lld %d bytes", (long long)offset, count);
Steve Frenchff7feac2005-11-15 16:45:16 -08002142
Steve French4c3130e2008-12-09 00:28:16 +00002143 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07002144 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00002145 } else {
Steve French8cc64c62005-10-03 13:49:43 -07002146 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00002147 if ((offset >> 32) > 0) {
2148 /* can not handle big offset for old srv */
2149 return -EIO;
2150 }
2151 }
Steve French8cc64c62005-10-03 13:49:43 -07002152 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002153 if (rc)
2154 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002155
2156 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
2157 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
2158
Linus Torvalds1da177e2005-04-16 15:20:36 -07002159 /* tcon and ses pointer are checked in smb_init */
2160 if (tcon->ses->server == NULL)
2161 return -ECONNABORTED;
2162
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002163 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002164 pSMB->Fid = netfid;
2165 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00002166 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002167 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002168 pSMB->Reserved = 0xFFFFFFFF;
2169 pSMB->WriteMode = 0;
2170 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002171
Linus Torvalds1da177e2005-04-16 15:20:36 -07002172 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00002173 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002174
Steve French3e844692005-10-03 13:37:24 -07002175 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
2176 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002177 /* header + 1 byte pad */
2178 smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
Steve French790fe572007-07-07 19:25:05 +00002179 if (wct == 14)
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002180 inc_rfc1001_len(pSMB, count + 1);
Steve French8cc64c62005-10-03 13:49:43 -07002181 else /* wct == 12 */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002182 inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
Steve French790fe572007-07-07 19:25:05 +00002183 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002184 pSMB->ByteCount = cpu_to_le16(count + 1);
2185 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00002186 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07002187 (struct smb_com_writex_req *)pSMB;
2188 pSMBW->ByteCount = cpu_to_le16(count + 5);
2189 }
Steve French3e844692005-10-03 13:37:24 -07002190 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00002191 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08002192 iov[0].iov_len = smb_hdr_len + 4;
2193 else /* wct == 12 pad bigger by four bytes */
2194 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00002195
Steve French3e844692005-10-03 13:37:24 -07002196
Pavel Shilovskyba9ad7252012-09-18 16:20:30 -07002197 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002198 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002199 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002200 cFYI(1, "Send error Write2 = %d", rc);
Steve French790fe572007-07-07 19:25:05 +00002201 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08002202 /* presumably this can not happen, but best to be safe */
2203 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002204 } else {
Steve Frenchad7a2922008-02-07 23:25:02 +00002205 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002206 *nbytes = le16_to_cpu(pSMBr->CountHigh);
2207 *nbytes = (*nbytes) << 16;
2208 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05302209
2210 /*
2211 * Mask off high 16 bits when bytes written as returned by the
2212 * server is greater than bytes requested by the client. OS/2
2213 * servers are known to set incorrect CountHigh values.
2214 */
2215 if (*nbytes > count)
2216 *nbytes &= 0xFFFF;
Steve French50c2f752007-07-13 00:33:32 +00002217 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002218
Steve French4b8f9302006-02-26 16:41:18 +00002219/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00002220 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002221 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00002222 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002223 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002224
Steve French50c2f752007-07-13 00:33:32 +00002225 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002226 since file handle passed in no longer valid */
2227
2228 return rc;
2229}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002230
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002231int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon,
2232 const __u16 netfid, const __u8 lock_type, const __u32 num_unlock,
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002233 const __u32 num_lock, LOCKING_ANDX_RANGE *buf)
2234{
2235 int rc = 0;
2236 LOCK_REQ *pSMB = NULL;
2237 struct kvec iov[2];
2238 int resp_buf_type;
2239 __u16 count;
2240
2241 cFYI(1, "cifs_lockv num lock %d num unlock %d", num_lock, num_unlock);
2242
2243 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2244 if (rc)
2245 return rc;
2246
2247 pSMB->Timeout = 0;
2248 pSMB->NumberOfLocks = cpu_to_le16(num_lock);
2249 pSMB->NumberOfUnlocks = cpu_to_le16(num_unlock);
2250 pSMB->LockType = lock_type;
2251 pSMB->AndXCommand = 0xFF; /* none */
2252 pSMB->Fid = netfid; /* netfid stays le */
2253
2254 count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2255 inc_rfc1001_len(pSMB, count);
2256 pSMB->ByteCount = cpu_to_le16(count);
2257
2258 iov[0].iov_base = (char *)pSMB;
2259 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 -
2260 (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2261 iov[1].iov_base = (char *)buf;
2262 iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2263
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002264 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002265 rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP);
2266 if (rc)
2267 cFYI(1, "Send error in cifs_lockv = %d", rc);
2268
2269 return rc;
2270}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002271
Linus Torvalds1da177e2005-04-16 15:20:36 -07002272int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002273CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002274 const __u16 smb_file_id, const __u32 netpid, const __u64 len,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002275 const __u64 offset, const __u32 numUnlock,
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002276 const __u32 numLock, const __u8 lockType,
2277 const bool waitFlag, const __u8 oplock_level)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002278{
2279 int rc = 0;
2280 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002281/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002282 int bytes_returned;
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002283 int flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002284 __u16 count;
2285
Joe Perchesb6b38f72010-04-21 03:50:45 +00002286 cFYI(1, "CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock);
Steve French46810cb2005-04-28 22:41:09 -07002287 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2288
Linus Torvalds1da177e2005-04-16 15:20:36 -07002289 if (rc)
2290 return rc;
2291
Steve French790fe572007-07-07 19:25:05 +00002292 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002293 /* no response expected */
2294 flags = CIFS_ASYNC_OP | CIFS_OBREAK_OP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002295 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00002296 } else if (waitFlag) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002297 flags = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002298 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
2299 } else {
2300 pSMB->Timeout = 0;
2301 }
2302
2303 pSMB->NumberOfLocks = cpu_to_le16(numLock);
2304 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
2305 pSMB->LockType = lockType;
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002306 pSMB->OplockLevel = oplock_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002307 pSMB->AndXCommand = 0xFF; /* none */
2308 pSMB->Fid = smb_file_id; /* netfid stays le */
2309
Steve French790fe572007-07-07 19:25:05 +00002310 if ((numLock != 0) || (numUnlock != 0)) {
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002311 pSMB->Locks[0].Pid = cpu_to_le16(netpid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002312 /* BB where to store pid high? */
2313 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
2314 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
2315 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
2316 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
2317 count = sizeof(LOCKING_ANDX_RANGE);
2318 } else {
2319 /* oplock break */
2320 count = 0;
2321 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002322 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323 pSMB->ByteCount = cpu_to_le16(count);
2324
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002325 if (waitFlag) {
2326 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002327 (struct smb_hdr *) pSMB, &bytes_returned);
Steve French133672e2007-11-13 22:41:37 +00002328 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002329 } else {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002330 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, flags);
Steve French133672e2007-11-13 22:41:37 +00002331 /* SMB buffer freed by function above */
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002332 }
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002333 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002334 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002335 cFYI(1, "Send error in Lock = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002336
Steve French50c2f752007-07-13 00:33:32 +00002337 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002338 since file handle passed in no longer valid */
2339 return rc;
2340}
2341
2342int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002343CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002344 const __u16 smb_file_id, const __u32 netpid,
2345 const loff_t start_offset, const __u64 len,
2346 struct file_lock *pLockData, const __u16 lock_type,
2347 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00002348{
2349 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2350 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00002351 struct cifs_posix_lock *parm_data;
2352 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00002353 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00002354 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00002355 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00002356 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00002357 struct kvec iov[1];
Steve French08547b02006-02-28 22:39:25 +00002358
Joe Perchesb6b38f72010-04-21 03:50:45 +00002359 cFYI(1, "Posix Lock");
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002360
Steve French08547b02006-02-28 22:39:25 +00002361 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
2362
2363 if (rc)
2364 return rc;
2365
2366 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
2367
Steve French50c2f752007-07-13 00:33:32 +00002368 params = 6;
Steve French08547b02006-02-28 22:39:25 +00002369 pSMB->MaxSetupCount = 0;
2370 pSMB->Reserved = 0;
2371 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00002372 pSMB->Reserved2 = 0;
2373 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2374 offset = param_offset + params;
2375
Steve French08547b02006-02-28 22:39:25 +00002376 count = sizeof(struct cifs_posix_lock);
2377 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002378 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00002379 pSMB->SetupCount = 1;
2380 pSMB->Reserved3 = 0;
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002381 if (pLockData)
Steve French08547b02006-02-28 22:39:25 +00002382 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2383 else
2384 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2385 byte_count = 3 /* pad */ + params + count;
2386 pSMB->DataCount = cpu_to_le16(count);
2387 pSMB->ParameterCount = cpu_to_le16(params);
2388 pSMB->TotalDataCount = pSMB->DataCount;
2389 pSMB->TotalParameterCount = pSMB->ParameterCount;
2390 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00002391 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00002392 (((char *) &pSMB->hdr.Protocol) + offset);
2393
2394 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00002395 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00002396 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00002397 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00002398 pSMB->Timeout = cpu_to_le32(-1);
2399 } else
2400 pSMB->Timeout = 0;
2401
Pavel Shilovsky4f6bcec2011-10-22 15:33:30 +04002402 parm_data->pid = cpu_to_le32(netpid);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002403 parm_data->start = cpu_to_le64(start_offset);
Steve Frenchcec6815a2006-05-30 18:07:17 +00002404 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00002405
2406 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00002407 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00002408 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
2409 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002410 inc_rfc1001_len(pSMB, byte_count);
Steve French08547b02006-02-28 22:39:25 +00002411 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002412 if (waitFlag) {
2413 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2414 (struct smb_hdr *) pSMBr, &bytes_returned);
2415 } else {
Steve French133672e2007-11-13 22:41:37 +00002416 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002417 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French133672e2007-11-13 22:41:37 +00002418 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
2419 &resp_buf_type, timeout);
2420 pSMB = NULL; /* request buf already freed by SendReceive2. Do
2421 not try to free it twice below on exit */
2422 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002423 }
2424
Steve French08547b02006-02-28 22:39:25 +00002425 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002426 cFYI(1, "Send error in Posix Lock = %d", rc);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002427 } else if (pLockData) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002428 /* lock structure can be returned on get */
2429 __u16 data_offset;
2430 __u16 data_count;
2431 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00002432
Jeff Layton820a8032011-05-04 08:05:26 -04002433 if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002434 rc = -EIO; /* bad smb */
2435 goto plk_err_exit;
2436 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002437 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2438 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00002439 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002440 rc = -EIO;
2441 goto plk_err_exit;
2442 }
2443 parm_data = (struct cifs_posix_lock *)
2444 ((char *)&pSMBr->hdr.Protocol + data_offset);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002445 if (parm_data->lock_type == __constant_cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002446 pLockData->fl_type = F_UNLCK;
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002447 else {
2448 if (parm_data->lock_type ==
2449 __constant_cpu_to_le16(CIFS_RDLCK))
2450 pLockData->fl_type = F_RDLCK;
2451 else if (parm_data->lock_type ==
2452 __constant_cpu_to_le16(CIFS_WRLCK))
2453 pLockData->fl_type = F_WRLCK;
2454
Steve French5443d132011-03-13 05:08:25 +00002455 pLockData->fl_start = le64_to_cpu(parm_data->start);
2456 pLockData->fl_end = pLockData->fl_start +
2457 le64_to_cpu(parm_data->length) - 1;
2458 pLockData->fl_pid = le32_to_cpu(parm_data->pid);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002459 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002460 }
Steve French50c2f752007-07-13 00:33:32 +00002461
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002462plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00002463 if (pSMB)
2464 cifs_small_buf_release(pSMB);
2465
Steve French133672e2007-11-13 22:41:37 +00002466 if (resp_buf_type == CIFS_SMALL_BUFFER)
2467 cifs_small_buf_release(iov[0].iov_base);
2468 else if (resp_buf_type == CIFS_LARGE_BUFFER)
2469 cifs_buf_release(iov[0].iov_base);
2470
Steve French08547b02006-02-28 22:39:25 +00002471 /* Note: On -EAGAIN error only caller can retry on handle based calls
2472 since file handle passed in no longer valid */
2473
2474 return rc;
2475}
2476
2477
2478int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002479CIFSSMBClose(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002480{
2481 int rc = 0;
2482 CLOSE_REQ *pSMB = NULL;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002483 cFYI(1, "In CIFSSMBClose");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002484
2485/* do not retry on dead session on close */
2486 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00002487 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002488 return 0;
2489 if (rc)
2490 return rc;
2491
Linus Torvalds1da177e2005-04-16 15:20:36 -07002492 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00002493 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002494 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002495 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002496 cifs_stats_inc(&tcon->stats.cifs_stats.num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002497 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00002498 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002499 /* EINTR is expected when user ctl-c to kill app */
Joe Perchesb6b38f72010-04-21 03:50:45 +00002500 cERROR(1, "Send error in Close = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002501 }
2502 }
2503
Linus Torvalds1da177e2005-04-16 15:20:36 -07002504 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00002505 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002506 rc = 0;
2507
2508 return rc;
2509}
2510
2511int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002512CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Steve Frenchb298f222009-02-21 21:17:43 +00002513{
2514 int rc = 0;
2515 FLUSH_REQ *pSMB = NULL;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002516 cFYI(1, "In CIFSSMBFlush");
Steve Frenchb298f222009-02-21 21:17:43 +00002517
2518 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
2519 if (rc)
2520 return rc;
2521
2522 pSMB->FileID = (__u16) smb_file_id;
2523 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002524 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002525 cifs_stats_inc(&tcon->stats.cifs_stats.num_flushes);
Steve Frenchb298f222009-02-21 21:17:43 +00002526 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002527 cERROR(1, "Send error in Flush = %d", rc);
Steve Frenchb298f222009-02-21 21:17:43 +00002528
2529 return rc;
2530}
2531
2532int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002533CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002534 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002535 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002536{
2537 int rc = 0;
2538 RENAME_REQ *pSMB = NULL;
2539 RENAME_RSP *pSMBr = NULL;
2540 int bytes_returned;
2541 int name_len, name_len2;
2542 __u16 count;
2543
Joe Perchesb6b38f72010-04-21 03:50:45 +00002544 cFYI(1, "In CIFSSMBRename");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002545renameRetry:
2546 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
2547 (void **) &pSMBr);
2548 if (rc)
2549 return rc;
2550
2551 pSMB->BufferFormat = 0x04;
2552 pSMB->SearchAttributes =
2553 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2554 ATTR_DIRECTORY);
2555
2556 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2557 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06002558 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, fromName,
2559 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002560 name_len++; /* trailing null */
2561 name_len *= 2;
2562 pSMB->OldFileName[name_len] = 0x04; /* pad */
2563 /* protocol requires ASCII signature byte on Unicode string */
2564 pSMB->OldFileName[name_len + 1] = 0x00;
2565 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002566 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2567 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002568 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2569 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002570 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002571 name_len = strnlen(fromName, PATH_MAX);
2572 name_len++; /* trailing null */
2573 strncpy(pSMB->OldFileName, fromName, name_len);
2574 name_len2 = strnlen(toName, PATH_MAX);
2575 name_len2++; /* trailing null */
2576 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2577 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2578 name_len2++; /* trailing null */
2579 name_len2++; /* signature byte */
2580 }
2581
2582 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002583 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002584 pSMB->ByteCount = cpu_to_le16(count);
2585
2586 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2587 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002588 cifs_stats_inc(&tcon->stats.cifs_stats.num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002589 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002590 cFYI(1, "Send error in rename = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002591
Linus Torvalds1da177e2005-04-16 15:20:36 -07002592 cifs_buf_release(pSMB);
2593
2594 if (rc == -EAGAIN)
2595 goto renameRetry;
2596
2597 return rc;
2598}
2599
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002600int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002601 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002602 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002603{
2604 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2605 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002606 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002607 char *data_offset;
2608 char dummy_string[30];
2609 int rc = 0;
2610 int bytes_returned = 0;
2611 int len_of_str;
2612 __u16 params, param_offset, offset, count, byte_count;
2613
Joe Perchesb6b38f72010-04-21 03:50:45 +00002614 cFYI(1, "Rename to File by handle");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002615 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2616 (void **) &pSMBr);
2617 if (rc)
2618 return rc;
2619
2620 params = 6;
2621 pSMB->MaxSetupCount = 0;
2622 pSMB->Reserved = 0;
2623 pSMB->Flags = 0;
2624 pSMB->Timeout = 0;
2625 pSMB->Reserved2 = 0;
2626 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2627 offset = param_offset + params;
2628
2629 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2630 rename_info = (struct set_file_rename *) data_offset;
2631 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002632 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002633 pSMB->SetupCount = 1;
2634 pSMB->Reserved3 = 0;
2635 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2636 byte_count = 3 /* pad */ + params;
2637 pSMB->ParameterCount = cpu_to_le16(params);
2638 pSMB->TotalParameterCount = pSMB->ParameterCount;
2639 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2640 pSMB->DataOffset = cpu_to_le16(offset);
2641 /* construct random name ".cifs_tmp<inodenum><mid>" */
2642 rename_info->overwrite = cpu_to_le32(1);
2643 rename_info->root_fid = 0;
2644 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002645 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002646 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
Steve Frenchacbbb762012-01-18 22:32:33 -06002647 len_of_str =
2648 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002649 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002650 } else {
Steve Frenchacbbb762012-01-18 22:32:33 -06002651 len_of_str =
2652 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002653 target_name, PATH_MAX, nls_codepage,
2654 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655 }
2656 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002657 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002658 byte_count += count;
2659 pSMB->DataCount = cpu_to_le16(count);
2660 pSMB->TotalDataCount = pSMB->DataCount;
2661 pSMB->Fid = netfid;
2662 pSMB->InformationLevel =
2663 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2664 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002665 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002666 pSMB->ByteCount = cpu_to_le16(byte_count);
2667 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002668 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002669 cifs_stats_inc(&pTcon->stats.cifs_stats.num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002670 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002671 cFYI(1, "Send error in Rename (by file handle) = %d", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07002672
Linus Torvalds1da177e2005-04-16 15:20:36 -07002673 cifs_buf_release(pSMB);
2674
2675 /* Note: On -EAGAIN error only caller can retry on handle based calls
2676 since file handle passed in no longer valid */
2677
2678 return rc;
2679}
2680
2681int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002682CIFSSMBCopy(const unsigned int xid, struct cifs_tcon *tcon,
2683 const char *fromName, const __u16 target_tid, const char *toName,
2684 const int flags, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002685{
2686 int rc = 0;
2687 COPY_REQ *pSMB = NULL;
2688 COPY_RSP *pSMBr = NULL;
2689 int bytes_returned;
2690 int name_len, name_len2;
2691 __u16 count;
2692
Joe Perchesb6b38f72010-04-21 03:50:45 +00002693 cFYI(1, "In CIFSSMBCopy");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002694copyRetry:
2695 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2696 (void **) &pSMBr);
2697 if (rc)
2698 return rc;
2699
2700 pSMB->BufferFormat = 0x04;
2701 pSMB->Tid2 = target_tid;
2702
2703 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2704
2705 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002706 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2707 fromName, PATH_MAX, nls_codepage,
2708 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002709 name_len++; /* trailing null */
2710 name_len *= 2;
2711 pSMB->OldFileName[name_len] = 0x04; /* pad */
2712 /* protocol requires ASCII signature byte on Unicode string */
2713 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002714 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002715 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2716 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002717 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2718 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002719 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002720 name_len = strnlen(fromName, PATH_MAX);
2721 name_len++; /* trailing null */
2722 strncpy(pSMB->OldFileName, fromName, name_len);
2723 name_len2 = strnlen(toName, PATH_MAX);
2724 name_len2++; /* trailing null */
2725 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2726 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2727 name_len2++; /* trailing null */
2728 name_len2++; /* signature byte */
2729 }
2730
2731 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002732 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002733 pSMB->ByteCount = cpu_to_le16(count);
2734
2735 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2736 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2737 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002738 cFYI(1, "Send error in copy = %d with %d files copied",
2739 rc, le16_to_cpu(pSMBr->CopyCount));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002740 }
Steve French0d817bc2008-05-22 02:02:03 +00002741 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002742
2743 if (rc == -EAGAIN)
2744 goto copyRetry;
2745
2746 return rc;
2747}
2748
2749int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002750CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002751 const char *fromName, const char *toName,
2752 const struct nls_table *nls_codepage)
2753{
2754 TRANSACTION2_SPI_REQ *pSMB = NULL;
2755 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2756 char *data_offset;
2757 int name_len;
2758 int name_len_target;
2759 int rc = 0;
2760 int bytes_returned = 0;
2761 __u16 params, param_offset, offset, byte_count;
2762
Joe Perchesb6b38f72010-04-21 03:50:45 +00002763 cFYI(1, "In Symlink Unix style");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002764createSymLinkRetry:
2765 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2766 (void **) &pSMBr);
2767 if (rc)
2768 return rc;
2769
2770 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2771 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06002772 cifs_strtoUTF16((__le16 *) pSMB->FileName, fromName,
2773 /* find define for this maxpathcomponent */
2774 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002775 name_len++; /* trailing null */
2776 name_len *= 2;
2777
Steve French50c2f752007-07-13 00:33:32 +00002778 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002779 name_len = strnlen(fromName, PATH_MAX);
2780 name_len++; /* trailing null */
2781 strncpy(pSMB->FileName, fromName, name_len);
2782 }
2783 params = 6 + name_len;
2784 pSMB->MaxSetupCount = 0;
2785 pSMB->Reserved = 0;
2786 pSMB->Flags = 0;
2787 pSMB->Timeout = 0;
2788 pSMB->Reserved2 = 0;
2789 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002790 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002791 offset = param_offset + params;
2792
2793 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2794 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2795 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06002796 cifs_strtoUTF16((__le16 *) data_offset, toName, PATH_MAX
2797 /* find define for this maxpathcomponent */
2798 , nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002799 name_len_target++; /* trailing null */
2800 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002801 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002802 name_len_target = strnlen(toName, PATH_MAX);
2803 name_len_target++; /* trailing null */
2804 strncpy(data_offset, toName, name_len_target);
2805 }
2806
2807 pSMB->MaxParameterCount = cpu_to_le16(2);
2808 /* BB find exact max on data count below from sess */
2809 pSMB->MaxDataCount = cpu_to_le16(1000);
2810 pSMB->SetupCount = 1;
2811 pSMB->Reserved3 = 0;
2812 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2813 byte_count = 3 /* pad */ + params + name_len_target;
2814 pSMB->DataCount = cpu_to_le16(name_len_target);
2815 pSMB->ParameterCount = cpu_to_le16(params);
2816 pSMB->TotalDataCount = pSMB->DataCount;
2817 pSMB->TotalParameterCount = pSMB->ParameterCount;
2818 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2819 pSMB->DataOffset = cpu_to_le16(offset);
2820 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2821 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002822 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002823 pSMB->ByteCount = cpu_to_le16(byte_count);
2824 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2825 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002826 cifs_stats_inc(&tcon->stats.cifs_stats.num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002827 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002828 cFYI(1, "Send error in SetPathInfo create symlink = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002829
Steve French0d817bc2008-05-22 02:02:03 +00002830 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002831
2832 if (rc == -EAGAIN)
2833 goto createSymLinkRetry;
2834
2835 return rc;
2836}
2837
2838int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002839CIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002840 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002841 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002842{
2843 TRANSACTION2_SPI_REQ *pSMB = NULL;
2844 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2845 char *data_offset;
2846 int name_len;
2847 int name_len_target;
2848 int rc = 0;
2849 int bytes_returned = 0;
2850 __u16 params, param_offset, offset, byte_count;
2851
Joe Perchesb6b38f72010-04-21 03:50:45 +00002852 cFYI(1, "In Create Hard link Unix style");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002853createHardLinkRetry:
2854 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2855 (void **) &pSMBr);
2856 if (rc)
2857 return rc;
2858
2859 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002860 name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, toName,
2861 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002862 name_len++; /* trailing null */
2863 name_len *= 2;
2864
Steve French50c2f752007-07-13 00:33:32 +00002865 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002866 name_len = strnlen(toName, PATH_MAX);
2867 name_len++; /* trailing null */
2868 strncpy(pSMB->FileName, toName, name_len);
2869 }
2870 params = 6 + name_len;
2871 pSMB->MaxSetupCount = 0;
2872 pSMB->Reserved = 0;
2873 pSMB->Flags = 0;
2874 pSMB->Timeout = 0;
2875 pSMB->Reserved2 = 0;
2876 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002877 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002878 offset = param_offset + params;
2879
2880 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2881 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2882 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06002883 cifsConvertToUTF16((__le16 *) data_offset, fromName,
2884 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002885 name_len_target++; /* trailing null */
2886 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002887 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002888 name_len_target = strnlen(fromName, PATH_MAX);
2889 name_len_target++; /* trailing null */
2890 strncpy(data_offset, fromName, name_len_target);
2891 }
2892
2893 pSMB->MaxParameterCount = cpu_to_le16(2);
2894 /* BB find exact max on data count below from sess*/
2895 pSMB->MaxDataCount = cpu_to_le16(1000);
2896 pSMB->SetupCount = 1;
2897 pSMB->Reserved3 = 0;
2898 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2899 byte_count = 3 /* pad */ + params + name_len_target;
2900 pSMB->ParameterCount = cpu_to_le16(params);
2901 pSMB->TotalParameterCount = pSMB->ParameterCount;
2902 pSMB->DataCount = cpu_to_le16(name_len_target);
2903 pSMB->TotalDataCount = pSMB->DataCount;
2904 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2905 pSMB->DataOffset = cpu_to_le16(offset);
2906 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2907 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002908 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002909 pSMB->ByteCount = cpu_to_le16(byte_count);
2910 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2911 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002912 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002913 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002914 cFYI(1, "Send error in SetPathInfo (hard link) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002915
2916 cifs_buf_release(pSMB);
2917 if (rc == -EAGAIN)
2918 goto createHardLinkRetry;
2919
2920 return rc;
2921}
2922
2923int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002924CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002925 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002926 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002927{
2928 int rc = 0;
2929 NT_RENAME_REQ *pSMB = NULL;
2930 RENAME_RSP *pSMBr = NULL;
2931 int bytes_returned;
2932 int name_len, name_len2;
2933 __u16 count;
2934
Joe Perchesb6b38f72010-04-21 03:50:45 +00002935 cFYI(1, "In CIFSCreateHardLink");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002936winCreateHardLinkRetry:
2937
2938 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2939 (void **) &pSMBr);
2940 if (rc)
2941 return rc;
2942
2943 pSMB->SearchAttributes =
2944 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2945 ATTR_DIRECTORY);
2946 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2947 pSMB->ClusterCount = 0;
2948
2949 pSMB->BufferFormat = 0x04;
2950
2951 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2952 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06002953 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, fromName,
2954 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002955 name_len++; /* trailing null */
2956 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05002957
2958 /* protocol specifies ASCII buffer format (0x04) for unicode */
2959 pSMB->OldFileName[name_len] = 0x04;
2960 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002961 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002962 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2963 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002964 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2965 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002966 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002967 name_len = strnlen(fromName, PATH_MAX);
2968 name_len++; /* trailing null */
2969 strncpy(pSMB->OldFileName, fromName, name_len);
2970 name_len2 = strnlen(toName, PATH_MAX);
2971 name_len2++; /* trailing null */
2972 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2973 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2974 name_len2++; /* trailing null */
2975 name_len2++; /* signature byte */
2976 }
2977
2978 count = 1 /* string type byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002979 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002980 pSMB->ByteCount = cpu_to_le16(count);
2981
2982 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2983 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002984 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002985 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002986 cFYI(1, "Send error in hard link (NT rename) = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00002987
Linus Torvalds1da177e2005-04-16 15:20:36 -07002988 cifs_buf_release(pSMB);
2989 if (rc == -EAGAIN)
2990 goto winCreateHardLinkRetry;
2991
2992 return rc;
2993}
2994
2995int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002996CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04002997 const unsigned char *searchName, char **symlinkinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002998 const struct nls_table *nls_codepage)
2999{
3000/* SMB_QUERY_FILE_UNIX_LINK */
3001 TRANSACTION2_QPI_REQ *pSMB = NULL;
3002 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3003 int rc = 0;
3004 int bytes_returned;
3005 int name_len;
3006 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04003007 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003008
Joe Perchesb6b38f72010-04-21 03:50:45 +00003009 cFYI(1, "In QPathSymLinkInfo (Unix) for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003010
3011querySymLinkRetry:
3012 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3013 (void **) &pSMBr);
3014 if (rc)
3015 return rc;
3016
3017 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3018 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003019 cifs_strtoUTF16((__le16 *) pSMB->FileName, searchName,
3020 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003021 name_len++; /* trailing null */
3022 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003023 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003024 name_len = strnlen(searchName, PATH_MAX);
3025 name_len++; /* trailing null */
3026 strncpy(pSMB->FileName, searchName, name_len);
3027 }
3028
3029 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3030 pSMB->TotalDataCount = 0;
3031 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04003032 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003033 pSMB->MaxSetupCount = 0;
3034 pSMB->Reserved = 0;
3035 pSMB->Flags = 0;
3036 pSMB->Timeout = 0;
3037 pSMB->Reserved2 = 0;
3038 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003039 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003040 pSMB->DataCount = 0;
3041 pSMB->DataOffset = 0;
3042 pSMB->SetupCount = 1;
3043 pSMB->Reserved3 = 0;
3044 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3045 byte_count = params + 1 /* pad */ ;
3046 pSMB->TotalParameterCount = cpu_to_le16(params);
3047 pSMB->ParameterCount = pSMB->TotalParameterCount;
3048 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
3049 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003050 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003051 pSMB->ByteCount = cpu_to_le16(byte_count);
3052
3053 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3054 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3055 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003056 cFYI(1, "Send error in QuerySymLinkInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003057 } else {
3058 /* decode response */
3059
3060 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003061 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003062 if (rc || get_bcc(&pSMBr->hdr) < 2)
Jeff Layton460b9692009-04-30 07:17:56 -04003063 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003064 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00003065 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04003066 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003067
Jeff Layton460b9692009-04-30 07:17:56 -04003068 data_start = ((char *) &pSMBr->hdr.Protocol) +
3069 le16_to_cpu(pSMBr->t2.DataOffset);
3070
Steve French0e0d2cf2009-05-01 05:27:32 +00003071 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3072 is_unicode = true;
3073 else
3074 is_unicode = false;
3075
Steve French737b7582005-04-28 22:41:06 -07003076 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchacbbb762012-01-18 22:32:33 -06003077 *symlinkinfo = cifs_strndup_from_utf16(data_start,
3078 count, is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04003079 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04003080 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003081 }
3082 }
3083 cifs_buf_release(pSMB);
3084 if (rc == -EAGAIN)
3085 goto querySymLinkRetry;
3086 return rc;
3087}
3088
Steve Frenchc52a9552011-02-24 06:16:22 +00003089#ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL
3090/*
3091 * Recent Windows versions now create symlinks more frequently
3092 * and they use the "reparse point" mechanism below. We can of course
3093 * do symlinks nicely to Samba and other servers which support the
3094 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
3095 * "MF" symlinks optionally, but for recent Windows we really need to
3096 * reenable the code below and fix the cifs_symlink callers to handle this.
3097 * In the interim this code has been moved to its own config option so
3098 * it is not compiled in by default until callers fixed up and more tested.
3099 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003100int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003101CIFSSMBQueryReparseLinkInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003102 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00003103 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003104 const struct nls_table *nls_codepage)
3105{
3106 int rc = 0;
3107 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00003108 struct smb_com_transaction_ioctl_req *pSMB;
3109 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003110
Joe Perchesb6b38f72010-04-21 03:50:45 +00003111 cFYI(1, "In Windows reparse style QueryLink for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003112 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3113 (void **) &pSMBr);
3114 if (rc)
3115 return rc;
3116
3117 pSMB->TotalParameterCount = 0 ;
3118 pSMB->TotalDataCount = 0;
3119 pSMB->MaxParameterCount = cpu_to_le32(2);
3120 /* BB find exact data count max from sess structure BB */
Jeff Laytonc974bef2011-10-11 06:41:32 -04003121 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003122 pSMB->MaxSetupCount = 4;
3123 pSMB->Reserved = 0;
3124 pSMB->ParameterOffset = 0;
3125 pSMB->DataCount = 0;
3126 pSMB->DataOffset = 0;
3127 pSMB->SetupCount = 4;
3128 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
3129 pSMB->ParameterCount = pSMB->TotalParameterCount;
3130 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
3131 pSMB->IsFsctl = 1; /* FSCTL */
3132 pSMB->IsRootFlag = 0;
3133 pSMB->Fid = fid; /* file handle always le */
3134 pSMB->ByteCount = 0;
3135
3136 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3137 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3138 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003139 cFYI(1, "Send error in QueryReparseLinkInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003140 } else { /* decode response */
3141 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
3142 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
Jeff Layton820a8032011-05-04 08:05:26 -04003143 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
3144 /* BB also check enough total bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003145 rc = -EIO; /* bad smb */
Steve Frenchafe48c32009-05-02 05:25:46 +00003146 goto qreparse_out;
3147 }
3148 if (data_count && (data_count < 2048)) {
3149 char *end_of_smb = 2 /* sizeof byte count */ +
Jeff Layton820a8032011-05-04 08:05:26 -04003150 get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003151
Steve Frenchafe48c32009-05-02 05:25:46 +00003152 struct reparse_data *reparse_buf =
Steve French50c2f752007-07-13 00:33:32 +00003153 (struct reparse_data *)
3154 ((char *)&pSMBr->hdr.Protocol
3155 + data_offset);
Steve Frenchafe48c32009-05-02 05:25:46 +00003156 if ((char *)reparse_buf >= end_of_smb) {
3157 rc = -EIO;
3158 goto qreparse_out;
3159 }
3160 if ((reparse_buf->LinkNamesBuf +
3161 reparse_buf->TargetNameOffset +
3162 reparse_buf->TargetNameLen) > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003163 cFYI(1, "reparse buf beyond SMB");
Steve Frenchafe48c32009-05-02 05:25:46 +00003164 rc = -EIO;
3165 goto qreparse_out;
3166 }
Steve French50c2f752007-07-13 00:33:32 +00003167
Steve Frenchafe48c32009-05-02 05:25:46 +00003168 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3169 cifs_from_ucs2(symlinkinfo, (__le16 *)
Steve French50c2f752007-07-13 00:33:32 +00003170 (reparse_buf->LinkNamesBuf +
3171 reparse_buf->TargetNameOffset),
Steve Frenchafe48c32009-05-02 05:25:46 +00003172 buflen,
3173 reparse_buf->TargetNameLen,
3174 nls_codepage, 0);
3175 } else { /* ASCII names */
3176 strncpy(symlinkinfo,
3177 reparse_buf->LinkNamesBuf +
3178 reparse_buf->TargetNameOffset,
3179 min_t(const int, buflen,
3180 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003181 }
Steve Frenchafe48c32009-05-02 05:25:46 +00003182 } else {
3183 rc = -EIO;
Joe Perchesb6b38f72010-04-21 03:50:45 +00003184 cFYI(1, "Invalid return data count on "
3185 "get reparse info ioctl");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003186 }
Steve Frenchafe48c32009-05-02 05:25:46 +00003187 symlinkinfo[buflen] = 0; /* just in case so the caller
3188 does not go off the end of the buffer */
Joe Perchesb6b38f72010-04-21 03:50:45 +00003189 cFYI(1, "readlink result - %s", symlinkinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003190 }
Steve French989c7e52009-05-02 05:32:20 +00003191
Linus Torvalds1da177e2005-04-16 15:20:36 -07003192qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07003193 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003194
3195 /* Note: On -EAGAIN error only caller can retry on handle based calls
3196 since file handle passed in no longer valid */
3197
3198 return rc;
3199}
Steve Frenchc52a9552011-02-24 06:16:22 +00003200#endif /* CIFS_SYMLINK_EXPERIMENTAL */ /* BB temporarily unused */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003201
3202#ifdef CONFIG_CIFS_POSIX
3203
3204/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00003205static void cifs_convert_ace(posix_acl_xattr_entry *ace,
3206 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003207{
3208 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08003209 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
3210 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
3211 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesb6b38f72010-04-21 03:50:45 +00003212 /* cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003213
3214 return;
3215}
3216
3217/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00003218static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
3219 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003220{
3221 int size = 0;
3222 int i;
3223 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00003224 struct cifs_posix_ace *pACE;
3225 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
3226 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003227
3228 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
3229 return -EOPNOTSUPP;
3230
Steve French790fe572007-07-07 19:25:05 +00003231 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003232 count = le16_to_cpu(cifs_acl->access_entry_count);
3233 pACE = &cifs_acl->ace_array[0];
3234 size = sizeof(struct cifs_posix_acl);
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) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003238 cFYI(1, "bad CIFS POSIX ACL size %d vs. %d",
3239 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003240 return -EINVAL;
3241 }
Steve French790fe572007-07-07 19:25:05 +00003242 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003243 count = le16_to_cpu(cifs_acl->access_entry_count);
3244 size = sizeof(struct cifs_posix_acl);
3245 size += sizeof(struct cifs_posix_ace) * count;
3246/* skip past access ACEs to get to default ACEs */
3247 pACE = &cifs_acl->ace_array[count];
3248 count = le16_to_cpu(cifs_acl->default_entry_count);
3249 size += sizeof(struct cifs_posix_ace) * count;
3250 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003251 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003252 return -EINVAL;
3253 } else {
3254 /* illegal type */
3255 return -EINVAL;
3256 }
3257
3258 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00003259 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00003260 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00003261 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003262 return -ERANGE;
3263 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08003264 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00003265 for (i = 0; i < count ; i++) {
3266 cifs_convert_ace(&local_acl->a_entries[i], pACE);
3267 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003268 }
3269 }
3270 return size;
3271}
3272
Steve French50c2f752007-07-13 00:33:32 +00003273static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
3274 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003275{
3276 __u16 rc = 0; /* 0 = ACL converted ok */
3277
Steve Frenchff7feac2005-11-15 16:45:16 -08003278 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
3279 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003280 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00003281 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003282 /* Probably no need to le convert -1 on any arch but can not hurt */
3283 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00003284 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08003285 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesb6b38f72010-04-21 03:50:45 +00003286 /*cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id);*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003287 return rc;
3288}
3289
3290/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00003291static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
3292 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003293{
3294 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00003295 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
3296 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003297 int count;
3298 int i;
3299
Steve French790fe572007-07-07 19:25:05 +00003300 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003301 return 0;
3302
3303 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesb6b38f72010-04-21 03:50:45 +00003304 cFYI(1, "setting acl with %d entries from buf of length %d and "
Steve French63135e02007-07-17 17:34:02 +00003305 "version of %d",
Joe Perchesb6b38f72010-04-21 03:50:45 +00003306 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00003307 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003308 cFYI(1, "unknown POSIX ACL version %d",
3309 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003310 return 0;
3311 }
3312 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00003313 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08003314 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00003315 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08003316 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003317 else {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003318 cFYI(1, "unknown ACL type %d", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003319 return 0;
3320 }
Steve French50c2f752007-07-13 00:33:32 +00003321 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003322 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
3323 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00003324 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003325 /* ACE not converted */
3326 break;
3327 }
3328 }
Steve French790fe572007-07-07 19:25:05 +00003329 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003330 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
3331 rc += sizeof(struct cifs_posix_acl);
3332 /* BB add check to make sure ACL does not overflow SMB */
3333 }
3334 return rc;
3335}
3336
3337int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003338CIFSSMBGetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003339 const unsigned char *searchName,
3340 char *acl_inf, const int buflen, const int acl_type,
3341 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003342{
3343/* SMB_QUERY_POSIX_ACL */
3344 TRANSACTION2_QPI_REQ *pSMB = NULL;
3345 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3346 int rc = 0;
3347 int bytes_returned;
3348 int name_len;
3349 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00003350
Joe Perchesb6b38f72010-04-21 03:50:45 +00003351 cFYI(1, "In GetPosixACL (Unix) for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003352
3353queryAclRetry:
3354 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3355 (void **) &pSMBr);
3356 if (rc)
3357 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003358
Linus Torvalds1da177e2005-04-16 15:20:36 -07003359 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3360 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003361 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3362 searchName, PATH_MAX, nls_codepage,
3363 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003364 name_len++; /* trailing null */
3365 name_len *= 2;
3366 pSMB->FileName[name_len] = 0;
3367 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00003368 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003369 name_len = strnlen(searchName, PATH_MAX);
3370 name_len++; /* trailing null */
3371 strncpy(pSMB->FileName, searchName, name_len);
3372 }
3373
3374 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3375 pSMB->TotalDataCount = 0;
3376 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00003377 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003378 pSMB->MaxDataCount = cpu_to_le16(4000);
3379 pSMB->MaxSetupCount = 0;
3380 pSMB->Reserved = 0;
3381 pSMB->Flags = 0;
3382 pSMB->Timeout = 0;
3383 pSMB->Reserved2 = 0;
3384 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003385 offsetof(struct smb_com_transaction2_qpi_req,
3386 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003387 pSMB->DataCount = 0;
3388 pSMB->DataOffset = 0;
3389 pSMB->SetupCount = 1;
3390 pSMB->Reserved3 = 0;
3391 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3392 byte_count = params + 1 /* pad */ ;
3393 pSMB->TotalParameterCount = cpu_to_le16(params);
3394 pSMB->ParameterCount = pSMB->TotalParameterCount;
3395 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
3396 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003397 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003398 pSMB->ByteCount = cpu_to_le16(byte_count);
3399
3400 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3401 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003402 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003403 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003404 cFYI(1, "Send error in Query POSIX ACL = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003405 } else {
3406 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00003407
Linus Torvalds1da177e2005-04-16 15:20:36 -07003408 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003409 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003410 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003411 rc = -EIO; /* bad smb */
3412 else {
3413 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3414 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3415 rc = cifs_copy_posix_acl(acl_inf,
3416 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00003417 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003418 }
3419 }
3420 cifs_buf_release(pSMB);
3421 if (rc == -EAGAIN)
3422 goto queryAclRetry;
3423 return rc;
3424}
3425
3426int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003427CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003428 const unsigned char *fileName,
3429 const char *local_acl, const int buflen,
3430 const int acl_type,
3431 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003432{
3433 struct smb_com_transaction2_spi_req *pSMB = NULL;
3434 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3435 char *parm_data;
3436 int name_len;
3437 int rc = 0;
3438 int bytes_returned = 0;
3439 __u16 params, byte_count, data_count, param_offset, offset;
3440
Joe Perchesb6b38f72010-04-21 03:50:45 +00003441 cFYI(1, "In SetPosixACL (Unix) for path %s", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003442setAclRetry:
3443 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003444 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003445 if (rc)
3446 return rc;
3447 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3448 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003449 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
3450 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003451 name_len++; /* trailing null */
3452 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003453 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003454 name_len = strnlen(fileName, PATH_MAX);
3455 name_len++; /* trailing null */
3456 strncpy(pSMB->FileName, fileName, name_len);
3457 }
3458 params = 6 + name_len;
3459 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003460 /* BB find max SMB size from sess */
3461 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003462 pSMB->MaxSetupCount = 0;
3463 pSMB->Reserved = 0;
3464 pSMB->Flags = 0;
3465 pSMB->Timeout = 0;
3466 pSMB->Reserved2 = 0;
3467 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003468 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003469 offset = param_offset + params;
3470 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
3471 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3472
3473 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00003474 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003475
Steve French790fe572007-07-07 19:25:05 +00003476 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003477 rc = -EOPNOTSUPP;
3478 goto setACLerrorExit;
3479 }
3480 pSMB->DataOffset = cpu_to_le16(offset);
3481 pSMB->SetupCount = 1;
3482 pSMB->Reserved3 = 0;
3483 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3484 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
3485 byte_count = 3 /* pad */ + params + data_count;
3486 pSMB->DataCount = cpu_to_le16(data_count);
3487 pSMB->TotalDataCount = pSMB->DataCount;
3488 pSMB->ParameterCount = cpu_to_le16(params);
3489 pSMB->TotalParameterCount = pSMB->ParameterCount;
3490 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003491 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003492 pSMB->ByteCount = cpu_to_le16(byte_count);
3493 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003494 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003495 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003496 cFYI(1, "Set POSIX ACL returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003497
3498setACLerrorExit:
3499 cifs_buf_release(pSMB);
3500 if (rc == -EAGAIN)
3501 goto setAclRetry;
3502 return rc;
3503}
3504
Steve Frenchf654bac2005-04-28 22:41:04 -07003505/* BB fix tabs in this function FIXME BB */
3506int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003507CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00003508 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07003509{
Steve French50c2f752007-07-13 00:33:32 +00003510 int rc = 0;
3511 struct smb_t2_qfi_req *pSMB = NULL;
3512 struct smb_t2_qfi_rsp *pSMBr = NULL;
3513 int bytes_returned;
3514 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07003515
Joe Perchesb6b38f72010-04-21 03:50:45 +00003516 cFYI(1, "In GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00003517 if (tcon == NULL)
3518 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07003519
3520GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003521 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3522 (void **) &pSMBr);
3523 if (rc)
3524 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003525
Steve Frenchad7a2922008-02-07 23:25:02 +00003526 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003527 pSMB->t2.TotalDataCount = 0;
3528 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3529 /* BB find exact max data count below from sess structure BB */
3530 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3531 pSMB->t2.MaxSetupCount = 0;
3532 pSMB->t2.Reserved = 0;
3533 pSMB->t2.Flags = 0;
3534 pSMB->t2.Timeout = 0;
3535 pSMB->t2.Reserved2 = 0;
3536 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3537 Fid) - 4);
3538 pSMB->t2.DataCount = 0;
3539 pSMB->t2.DataOffset = 0;
3540 pSMB->t2.SetupCount = 1;
3541 pSMB->t2.Reserved3 = 0;
3542 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3543 byte_count = params + 1 /* pad */ ;
3544 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3545 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3546 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3547 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003548 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003549 inc_rfc1001_len(pSMB, byte_count);
Steve French790fe572007-07-07 19:25:05 +00003550 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003551
Steve French790fe572007-07-07 19:25:05 +00003552 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3553 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3554 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003555 cFYI(1, "error %d in GetExtAttr", rc);
Steve French790fe572007-07-07 19:25:05 +00003556 } else {
3557 /* decode response */
3558 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003559 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003560 if (rc || get_bcc(&pSMBr->hdr) < 2)
Steve French790fe572007-07-07 19:25:05 +00003561 /* If rc should we check for EOPNOSUPP and
3562 disable the srvino flag? or in caller? */
3563 rc = -EIO; /* bad smb */
3564 else {
3565 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3566 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3567 struct file_chattr_info *pfinfo;
3568 /* BB Do we need a cast or hash here ? */
3569 if (count != 16) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003570 cFYI(1, "Illegal size ret in GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00003571 rc = -EIO;
3572 goto GetExtAttrOut;
3573 }
3574 pfinfo = (struct file_chattr_info *)
3575 (data_offset + (char *) &pSMBr->hdr.Protocol);
3576 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003577 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003578 }
3579 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003580GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003581 cifs_buf_release(pSMB);
3582 if (rc == -EAGAIN)
3583 goto GetExtAttrRetry;
3584 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003585}
3586
Steve Frenchf654bac2005-04-28 22:41:04 -07003587#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003588
Jeff Layton79df1ba2010-12-06 12:52:08 -05003589#ifdef CONFIG_CIFS_ACL
3590/*
3591 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3592 * all NT TRANSACTS that we init here have total parm and data under about 400
3593 * bytes (to fit in small cifs buffer size), which is the case so far, it
3594 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3595 * returned setup area) and MaxParameterCount (returned parms size) must be set
3596 * by caller
3597 */
3598static int
3599smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French96daf2b2011-05-27 04:34:02 +00003600 const int parm_len, struct cifs_tcon *tcon,
Jeff Layton79df1ba2010-12-06 12:52:08 -05003601 void **ret_buf)
3602{
3603 int rc;
3604 __u32 temp_offset;
3605 struct smb_com_ntransact_req *pSMB;
3606
3607 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3608 (void **)&pSMB);
3609 if (rc)
3610 return rc;
3611 *ret_buf = (void *)pSMB;
3612 pSMB->Reserved = 0;
3613 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3614 pSMB->TotalDataCount = 0;
Jeff Laytonc974bef2011-10-11 06:41:32 -04003615 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003616 pSMB->ParameterCount = pSMB->TotalParameterCount;
3617 pSMB->DataCount = pSMB->TotalDataCount;
3618 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3619 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3620 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3621 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3622 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3623 pSMB->SubCommand = cpu_to_le16(sub_command);
3624 return 0;
3625}
3626
3627static int
3628validate_ntransact(char *buf, char **ppparm, char **ppdata,
3629 __u32 *pparmlen, __u32 *pdatalen)
3630{
3631 char *end_of_smb;
3632 __u32 data_count, data_offset, parm_count, parm_offset;
3633 struct smb_com_ntransact_rsp *pSMBr;
Jeff Layton820a8032011-05-04 08:05:26 -04003634 u16 bcc;
Jeff Layton79df1ba2010-12-06 12:52:08 -05003635
3636 *pdatalen = 0;
3637 *pparmlen = 0;
3638
3639 if (buf == NULL)
3640 return -EINVAL;
3641
3642 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3643
Jeff Layton820a8032011-05-04 08:05:26 -04003644 bcc = get_bcc(&pSMBr->hdr);
3645 end_of_smb = 2 /* sizeof byte count */ + bcc +
Jeff Layton79df1ba2010-12-06 12:52:08 -05003646 (char *)&pSMBr->ByteCount;
3647
3648 data_offset = le32_to_cpu(pSMBr->DataOffset);
3649 data_count = le32_to_cpu(pSMBr->DataCount);
3650 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3651 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3652
3653 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3654 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3655
3656 /* should we also check that parm and data areas do not overlap? */
3657 if (*ppparm > end_of_smb) {
3658 cFYI(1, "parms start after end of smb");
3659 return -EINVAL;
3660 } else if (parm_count + *ppparm > end_of_smb) {
3661 cFYI(1, "parm end after end of smb");
3662 return -EINVAL;
3663 } else if (*ppdata > end_of_smb) {
3664 cFYI(1, "data starts after end of smb");
3665 return -EINVAL;
3666 } else if (data_count + *ppdata > end_of_smb) {
3667 cFYI(1, "data %p + count %d (%p) past smb end %p start %p",
3668 *ppdata, data_count, (data_count + *ppdata),
3669 end_of_smb, pSMBr);
3670 return -EINVAL;
Jeff Layton820a8032011-05-04 08:05:26 -04003671 } else if (parm_count + data_count > bcc) {
Jeff Layton79df1ba2010-12-06 12:52:08 -05003672 cFYI(1, "parm count and data count larger than SMB");
3673 return -EINVAL;
3674 }
3675 *pdatalen = data_count;
3676 *pparmlen = parm_count;
3677 return 0;
3678}
3679
Steve French0a4b92c2006-01-12 15:44:21 -08003680/* Get Security Descriptor (by handle) from remote server for a file or dir */
3681int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003682CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003683 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003684{
3685 int rc = 0;
3686 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003687 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003688 struct kvec iov[1];
3689
Joe Perchesb6b38f72010-04-21 03:50:45 +00003690 cFYI(1, "GetCifsACL");
Steve French0a4b92c2006-01-12 15:44:21 -08003691
Steve French630f3f0c2007-10-25 21:17:17 +00003692 *pbuflen = 0;
3693 *acl_inf = NULL;
3694
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003695 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003696 8 /* parm len */, tcon, (void **) &pSMB);
3697 if (rc)
3698 return rc;
3699
3700 pSMB->MaxParameterCount = cpu_to_le32(4);
3701 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3702 pSMB->MaxSetupCount = 0;
3703 pSMB->Fid = fid; /* file handle always le */
3704 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3705 CIFS_ACL_DACL);
3706 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003707 inc_rfc1001_len(pSMB, 11);
Steve French0a4b92c2006-01-12 15:44:21 -08003708 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003709 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French0a4b92c2006-01-12 15:44:21 -08003710
Steve Frencha761ac52007-10-18 21:45:27 +00003711 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Jeff Layton77499812011-01-11 07:24:23 -05003712 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003713 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Steve French0a4b92c2006-01-12 15:44:21 -08003714 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003715 cFYI(1, "Send error in QuerySecDesc = %d", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08003716 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003717 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003718 __u32 parm_len;
3719 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003720 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003721 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003722
3723/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003724 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003725 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003726 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003727 goto qsec_out;
3728 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3729
Joe Perchesb6b38f72010-04-21 03:50:45 +00003730 cFYI(1, "smb %p parm %p data %p", pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08003731
3732 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3733 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003734 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003735 goto qsec_out;
3736 }
3737
3738/* BB check that data area is minimum length and as big as acl_len */
3739
Steve Frenchaf6f4612007-10-16 18:40:37 +00003740 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003741 if (acl_len != *pbuflen) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003742 cERROR(1, "acl length %d does not match %d",
3743 acl_len, *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003744 if (*pbuflen > acl_len)
3745 *pbuflen = acl_len;
3746 }
Steve French0a4b92c2006-01-12 15:44:21 -08003747
Steve French630f3f0c2007-10-25 21:17:17 +00003748 /* check if buffer is big enough for the acl
3749 header followed by the smallest SID */
3750 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3751 (*pbuflen >= 64 * 1024)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003752 cERROR(1, "bad acl length %d", *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003753 rc = -EINVAL;
3754 *pbuflen = 0;
3755 } else {
3756 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3757 if (*acl_inf == NULL) {
3758 *pbuflen = 0;
3759 rc = -ENOMEM;
3760 }
3761 memcpy(*acl_inf, pdata, *pbuflen);
3762 }
Steve French0a4b92c2006-01-12 15:44:21 -08003763 }
3764qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003765 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003766 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003767 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003768 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003769/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003770 return rc;
3771}
Steve French97837582007-12-31 07:47:21 +00003772
3773int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003774CIFSSMBSetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003775 struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
Steve French97837582007-12-31 07:47:21 +00003776{
3777 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3778 int rc = 0;
3779 int bytes_returned = 0;
3780 SET_SEC_DESC_REQ *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003781 void *pSMBr;
Steve French97837582007-12-31 07:47:21 +00003782
3783setCifsAclRetry:
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003784 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, &pSMBr);
Steve French97837582007-12-31 07:47:21 +00003785 if (rc)
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003786 return rc;
Steve French97837582007-12-31 07:47:21 +00003787
3788 pSMB->MaxSetupCount = 0;
3789 pSMB->Reserved = 0;
3790
3791 param_count = 8;
3792 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3793 data_count = acllen;
3794 data_offset = param_offset + param_count;
3795 byte_count = 3 /* pad */ + param_count;
3796
3797 pSMB->DataCount = cpu_to_le32(data_count);
3798 pSMB->TotalDataCount = pSMB->DataCount;
3799 pSMB->MaxParameterCount = cpu_to_le32(4);
3800 pSMB->MaxDataCount = cpu_to_le32(16384);
3801 pSMB->ParameterCount = cpu_to_le32(param_count);
3802 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3803 pSMB->TotalParameterCount = pSMB->ParameterCount;
3804 pSMB->DataOffset = cpu_to_le32(data_offset);
3805 pSMB->SetupCount = 0;
3806 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3807 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3808
3809 pSMB->Fid = fid; /* file handle always le */
3810 pSMB->Reserved2 = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003811 pSMB->AclFlags = cpu_to_le32(aclflag);
Steve French97837582007-12-31 07:47:21 +00003812
3813 if (pntsd && acllen) {
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003814 memcpy((char *)pSMBr + offsetof(struct smb_hdr, Protocol) +
3815 data_offset, pntsd, acllen);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003816 inc_rfc1001_len(pSMB, byte_count + data_count);
Steve French97837582007-12-31 07:47:21 +00003817 } else
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003818 inc_rfc1001_len(pSMB, byte_count);
Steve French97837582007-12-31 07:47:21 +00003819
3820 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3821 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3822
Joe Perchesb6b38f72010-04-21 03:50:45 +00003823 cFYI(1, "SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00003824 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003825 cFYI(1, "Set CIFS ACL returned %d", rc);
Steve French97837582007-12-31 07:47:21 +00003826 cifs_buf_release(pSMB);
3827
3828 if (rc == -EAGAIN)
3829 goto setCifsAclRetry;
3830
3831 return (rc);
3832}
3833
Jeff Layton79df1ba2010-12-06 12:52:08 -05003834#endif /* CONFIG_CIFS_ACL */
Steve French0a4b92c2006-01-12 15:44:21 -08003835
Steve French6b8edfe2005-08-23 20:26:03 -07003836/* Legacy Query Path Information call for lookup to old servers such
3837 as Win9x/WinME */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003838int
3839SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon,
3840 const char *search_name, FILE_ALL_INFO *data,
3841 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003842{
Steve Frenchad7a2922008-02-07 23:25:02 +00003843 QUERY_INFORMATION_REQ *pSMB;
3844 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003845 int rc = 0;
3846 int bytes_returned;
3847 int name_len;
3848
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003849 cFYI(1, "In SMBQPath path %s", search_name);
Steve French6b8edfe2005-08-23 20:26:03 -07003850QInfRetry:
3851 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003852 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003853 if (rc)
3854 return rc;
3855
3856 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3857 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003858 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003859 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06003860 remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003861 name_len++; /* trailing null */
3862 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003863 } else {
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003864 name_len = strnlen(search_name, PATH_MAX);
Steve French6b8edfe2005-08-23 20:26:03 -07003865 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003866 strncpy(pSMB->FileName, search_name, name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07003867 }
3868 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003869 name_len++; /* account for buffer type byte */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003870 inc_rfc1001_len(pSMB, (__u16)name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07003871 pSMB->ByteCount = cpu_to_le16(name_len);
3872
3873 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003874 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003875 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003876 cFYI(1, "Send error in QueryInfo = %d", rc);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003877 } else if (data) {
Steve French1bd5bbc2006-09-28 03:35:57 +00003878 struct timespec ts;
3879 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00003880
3881 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003882 /* BB FIXME - add time zone adjustment BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003883 memset(data, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003884 ts.tv_nsec = 0;
3885 ts.tv_sec = time;
3886 /* decode time fields */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003887 data->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
3888 data->LastWriteTime = data->ChangeTime;
3889 data->LastAccessTime = 0;
3890 data->AllocationSize =
Steve French70ca7342005-09-22 16:32:06 -07003891 cpu_to_le64(le32_to_cpu(pSMBr->size));
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003892 data->EndOfFile = data->AllocationSize;
3893 data->Attributes =
Steve French70ca7342005-09-22 16:32:06 -07003894 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003895 } else
3896 rc = -EIO; /* bad buffer passed in */
3897
3898 cifs_buf_release(pSMB);
3899
3900 if (rc == -EAGAIN)
3901 goto QInfRetry;
3902
3903 return rc;
3904}
3905
Jeff Laytonbcd53572010-02-12 07:44:16 -05003906int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003907CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonbcd53572010-02-12 07:44:16 -05003908 u16 netfid, FILE_ALL_INFO *pFindData)
3909{
3910 struct smb_t2_qfi_req *pSMB = NULL;
3911 struct smb_t2_qfi_rsp *pSMBr = NULL;
3912 int rc = 0;
3913 int bytes_returned;
3914 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07003915
Jeff Laytonbcd53572010-02-12 07:44:16 -05003916QFileInfoRetry:
3917 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3918 (void **) &pSMBr);
3919 if (rc)
3920 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07003921
Jeff Laytonbcd53572010-02-12 07:44:16 -05003922 params = 2 /* level */ + 2 /* fid */;
3923 pSMB->t2.TotalDataCount = 0;
3924 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3925 /* BB find exact max data count below from sess structure BB */
3926 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3927 pSMB->t2.MaxSetupCount = 0;
3928 pSMB->t2.Reserved = 0;
3929 pSMB->t2.Flags = 0;
3930 pSMB->t2.Timeout = 0;
3931 pSMB->t2.Reserved2 = 0;
3932 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3933 Fid) - 4);
3934 pSMB->t2.DataCount = 0;
3935 pSMB->t2.DataOffset = 0;
3936 pSMB->t2.SetupCount = 1;
3937 pSMB->t2.Reserved3 = 0;
3938 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3939 byte_count = params + 1 /* pad */ ;
3940 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3941 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3942 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3943 pSMB->Pad = 0;
3944 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003945 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003946
3947 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3948 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3949 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00003950 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003951 } else { /* decode response */
3952 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3953
3954 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3955 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04003956 else if (get_bcc(&pSMBr->hdr) < 40)
Jeff Laytonbcd53572010-02-12 07:44:16 -05003957 rc = -EIO; /* bad smb */
3958 else if (pFindData) {
3959 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3960 memcpy((char *) pFindData,
3961 (char *) &pSMBr->hdr.Protocol +
3962 data_offset, sizeof(FILE_ALL_INFO));
3963 } else
3964 rc = -ENOMEM;
3965 }
3966 cifs_buf_release(pSMB);
3967 if (rc == -EAGAIN)
3968 goto QFileInfoRetry;
3969
3970 return rc;
3971}
Steve French6b8edfe2005-08-23 20:26:03 -07003972
Linus Torvalds1da177e2005-04-16 15:20:36 -07003973int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003974CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003975 const char *search_name, FILE_ALL_INFO *data,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003976 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003977 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003978{
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003979 /* level 263 SMB_QUERY_FILE_ALL_INFO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003980 TRANSACTION2_QPI_REQ *pSMB = NULL;
3981 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3982 int rc = 0;
3983 int bytes_returned;
3984 int name_len;
3985 __u16 params, byte_count;
3986
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003987 /* cFYI(1, "In QPathInfo path %s", search_name); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003988QPathInfoRetry:
3989 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3990 (void **) &pSMBr);
3991 if (rc)
3992 return rc;
3993
3994 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3995 name_len =
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003996 cifsConvertToUTF16((__le16 *) pSMB->FileName, search_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06003997 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003998 name_len++; /* trailing null */
3999 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004000 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004001 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004002 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004003 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004004 }
4005
Steve French50c2f752007-07-13 00:33:32 +00004006 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004007 pSMB->TotalDataCount = 0;
4008 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004009 /* BB find exact max SMB PDU from sess structure BB */
4010 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004011 pSMB->MaxSetupCount = 0;
4012 pSMB->Reserved = 0;
4013 pSMB->Flags = 0;
4014 pSMB->Timeout = 0;
4015 pSMB->Reserved2 = 0;
4016 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004017 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004018 pSMB->DataCount = 0;
4019 pSMB->DataOffset = 0;
4020 pSMB->SetupCount = 1;
4021 pSMB->Reserved3 = 0;
4022 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4023 byte_count = params + 1 /* pad */ ;
4024 pSMB->TotalParameterCount = cpu_to_le16(params);
4025 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00004026 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004027 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
4028 else
4029 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004030 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004031 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004032 pSMB->ByteCount = cpu_to_le16(byte_count);
4033
4034 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4035 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4036 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004037 cFYI(1, "Send error in QPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004038 } else { /* decode response */
4039 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4040
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004041 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4042 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004043 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004044 rc = -EIO; /* bad smb */
Jeff Layton820a8032011-05-04 08:05:26 -04004045 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
Steve French50c2f752007-07-13 00:33:32 +00004046 rc = -EIO; /* 24 or 26 expected but we do not read
4047 last field */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004048 else if (data) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004049 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004050 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00004051
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004052 /*
4053 * On legacy responses we do not read the last field,
4054 * EAsize, fortunately since it varies by subdialect and
4055 * also note it differs on Set vs Get, ie two bytes or 4
4056 * bytes depending but we don't care here.
4057 */
Steve Frenchad7a2922008-02-07 23:25:02 +00004058 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004059 size = sizeof(FILE_INFO_STANDARD);
4060 else
4061 size = sizeof(FILE_ALL_INFO);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004062 memcpy((char *) data, (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004063 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004064 } else
4065 rc = -ENOMEM;
4066 }
4067 cifs_buf_release(pSMB);
4068 if (rc == -EAGAIN)
4069 goto QPathInfoRetry;
4070
4071 return rc;
4072}
4073
4074int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004075CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004076 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
4077{
4078 struct smb_t2_qfi_req *pSMB = NULL;
4079 struct smb_t2_qfi_rsp *pSMBr = NULL;
4080 int rc = 0;
4081 int bytes_returned;
4082 __u16 params, byte_count;
4083
4084UnixQFileInfoRetry:
4085 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4086 (void **) &pSMBr);
4087 if (rc)
4088 return rc;
4089
4090 params = 2 /* level */ + 2 /* fid */;
4091 pSMB->t2.TotalDataCount = 0;
4092 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4093 /* BB find exact max data count below from sess structure BB */
4094 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4095 pSMB->t2.MaxSetupCount = 0;
4096 pSMB->t2.Reserved = 0;
4097 pSMB->t2.Flags = 0;
4098 pSMB->t2.Timeout = 0;
4099 pSMB->t2.Reserved2 = 0;
4100 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4101 Fid) - 4);
4102 pSMB->t2.DataCount = 0;
4103 pSMB->t2.DataOffset = 0;
4104 pSMB->t2.SetupCount = 1;
4105 pSMB->t2.Reserved3 = 0;
4106 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4107 byte_count = params + 1 /* pad */ ;
4108 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4109 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4110 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4111 pSMB->Pad = 0;
4112 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004113 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004114
4115 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4116 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4117 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00004118 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004119 } else { /* decode response */
4120 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4121
Jeff Layton820a8032011-05-04 08:05:26 -04004122 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004123 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response. "
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004124 "Unix Extensions can be disabled on mount "
Steve Frenchf19159d2010-04-21 04:12:10 +00004125 "by specifying the nosfu mount option.");
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004126 rc = -EIO; /* bad smb */
4127 } else {
4128 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4129 memcpy((char *) pFindData,
4130 (char *) &pSMBr->hdr.Protocol +
4131 data_offset,
4132 sizeof(FILE_UNIX_BASIC_INFO));
4133 }
4134 }
4135
4136 cifs_buf_release(pSMB);
4137 if (rc == -EAGAIN)
4138 goto UnixQFileInfoRetry;
4139
4140 return rc;
4141}
4142
4143int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004144CIFSSMBUnixQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004145 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00004146 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07004147 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004148{
4149/* SMB_QUERY_FILE_UNIX_BASIC */
4150 TRANSACTION2_QPI_REQ *pSMB = NULL;
4151 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4152 int rc = 0;
4153 int bytes_returned = 0;
4154 int name_len;
4155 __u16 params, byte_count;
4156
Joe Perchesb6b38f72010-04-21 03:50:45 +00004157 cFYI(1, "In QPathInfo (Unix) the path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004158UnixQPathInfoRetry:
4159 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4160 (void **) &pSMBr);
4161 if (rc)
4162 return rc;
4163
4164 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4165 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004166 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4167 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004168 name_len++; /* trailing null */
4169 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004170 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004171 name_len = strnlen(searchName, PATH_MAX);
4172 name_len++; /* trailing null */
4173 strncpy(pSMB->FileName, searchName, name_len);
4174 }
4175
Steve French50c2f752007-07-13 00:33:32 +00004176 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004177 pSMB->TotalDataCount = 0;
4178 pSMB->MaxParameterCount = cpu_to_le16(2);
4179 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00004180 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004181 pSMB->MaxSetupCount = 0;
4182 pSMB->Reserved = 0;
4183 pSMB->Flags = 0;
4184 pSMB->Timeout = 0;
4185 pSMB->Reserved2 = 0;
4186 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004187 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004188 pSMB->DataCount = 0;
4189 pSMB->DataOffset = 0;
4190 pSMB->SetupCount = 1;
4191 pSMB->Reserved3 = 0;
4192 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4193 byte_count = params + 1 /* pad */ ;
4194 pSMB->TotalParameterCount = cpu_to_le16(params);
4195 pSMB->ParameterCount = pSMB->TotalParameterCount;
4196 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4197 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004198 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004199 pSMB->ByteCount = cpu_to_le16(byte_count);
4200
4201 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4202 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4203 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004204 cFYI(1, "Send error in QPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004205 } else { /* decode response */
4206 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4207
Jeff Layton820a8032011-05-04 08:05:26 -04004208 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004209 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response. "
Steve French1e71f252007-09-20 15:30:07 +00004210 "Unix Extensions can be disabled on mount "
Joe Perchesb6b38f72010-04-21 03:50:45 +00004211 "by specifying the nosfu mount option.");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004212 rc = -EIO; /* bad smb */
4213 } else {
4214 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4215 memcpy((char *) pFindData,
4216 (char *) &pSMBr->hdr.Protocol +
4217 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00004218 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004219 }
4220 }
4221 cifs_buf_release(pSMB);
4222 if (rc == -EAGAIN)
4223 goto UnixQPathInfoRetry;
4224
4225 return rc;
4226}
4227
Linus Torvalds1da177e2005-04-16 15:20:36 -07004228/* xid, tcon, searchName and codepage are input parms, rest are returned */
4229int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004230CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004231 const char *searchName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004232 const struct nls_table *nls_codepage,
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004233 __u16 *pnetfid, __u16 search_flags,
Steve French50c2f752007-07-13 00:33:32 +00004234 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004235{
4236/* level 257 SMB_ */
4237 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
4238 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004239 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004240 int rc = 0;
4241 int bytes_returned = 0;
4242 int name_len;
4243 __u16 params, byte_count;
4244
Joe Perchesb6b38f72010-04-21 03:50:45 +00004245 cFYI(1, "In FindFirst for %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004246
4247findFirstRetry:
4248 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4249 (void **) &pSMBr);
4250 if (rc)
4251 return rc;
4252
4253 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4254 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004255 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4256 PATH_MAX, nls_codepage, remap);
Steve French737b7582005-04-28 22:41:06 -07004257 /* We can not add the asterik earlier in case
4258 it got remapped to 0xF03A as if it were part of the
4259 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004260 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07004261 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07004262 pSMB->FileName[name_len+1] = 0;
4263 pSMB->FileName[name_len+2] = '*';
4264 pSMB->FileName[name_len+3] = 0;
4265 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004266 pSMB->FileName[name_len] = 0; /* null terminate just in case */
4267 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07004268 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004269 } else { /* BB add check for overrun of SMB buf BB */
4270 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004271/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00004272 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004273 free buffer exit; BB */
4274 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07004275 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07004276 pSMB->FileName[name_len+1] = '*';
4277 pSMB->FileName[name_len+2] = 0;
4278 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004279 }
4280
4281 params = 12 + name_len /* includes null */ ;
4282 pSMB->TotalDataCount = 0; /* no EAs */
4283 pSMB->MaxParameterCount = cpu_to_le16(10);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004284 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004285 pSMB->MaxSetupCount = 0;
4286 pSMB->Reserved = 0;
4287 pSMB->Flags = 0;
4288 pSMB->Timeout = 0;
4289 pSMB->Reserved2 = 0;
4290 byte_count = params + 1 /* pad */ ;
4291 pSMB->TotalParameterCount = cpu_to_le16(params);
4292 pSMB->ParameterCount = pSMB->TotalParameterCount;
4293 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00004294 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
4295 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004296 pSMB->DataCount = 0;
4297 pSMB->DataOffset = 0;
4298 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
4299 pSMB->Reserved3 = 0;
4300 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
4301 pSMB->SearchAttributes =
4302 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
4303 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00004304 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004305 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004306 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4307
4308 /* BB what should we set StorageType to? Does it matter? BB */
4309 pSMB->SearchStorageType = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004310 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004311 pSMB->ByteCount = cpu_to_le16(byte_count);
4312
4313 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4314 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004315 cifs_stats_inc(&tcon->stats.cifs_stats.num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004316
Steve French88274812006-03-09 22:21:45 +00004317 if (rc) {/* BB add logic to retry regular search if Unix search
4318 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004319 /* BB Add code to handle unsupported level rc */
Joe Perchesb6b38f72010-04-21 03:50:45 +00004320 cFYI(1, "Error in FindFirst = %d", rc);
Steve French1982c342005-08-17 12:38:22 -07004321
Steve French88274812006-03-09 22:21:45 +00004322 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004323
4324 /* BB eventually could optimize out free and realloc of buf */
4325 /* for this case */
4326 if (rc == -EAGAIN)
4327 goto findFirstRetry;
4328 } else { /* decode response */
4329 /* BB remember to free buffer if error BB */
4330 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00004331 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004332 unsigned int lnoff;
4333
Linus Torvalds1da177e2005-04-16 15:20:36 -07004334 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004335 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004336 else
Steve French4b18f2a2008-04-29 00:06:05 +00004337 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004338
4339 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004340 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00004341 psrch_inf->srch_entries_start =
4342 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004343 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004344 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
4345 le16_to_cpu(pSMBr->t2.ParameterOffset));
4346
Steve French790fe572007-07-07 19:25:05 +00004347 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004348 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004349 else
Steve French4b18f2a2008-04-29 00:06:05 +00004350 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004351
Steve French50c2f752007-07-13 00:33:32 +00004352 psrch_inf->entries_in_buffer =
4353 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00004354 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004355 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004356 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004357 if (CIFSMaxBufSize < lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004358 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00004359 psrch_inf->last_entry = NULL;
4360 return rc;
4361 }
4362
Steve French0752f152008-10-07 20:03:33 +00004363 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00004364 lnoff;
4365
Linus Torvalds1da177e2005-04-16 15:20:36 -07004366 *pnetfid = parms->SearchHandle;
4367 } else {
4368 cifs_buf_release(pSMB);
4369 }
4370 }
4371
4372 return rc;
4373}
4374
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004375int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
4376 __u16 searchHandle, __u16 search_flags,
4377 struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004378{
4379 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
4380 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004381 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004382 char *response_data;
4383 int rc = 0;
Jeff Layton9438fab2011-08-23 07:21:28 -04004384 int bytes_returned;
4385 unsigned int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004386 __u16 params, byte_count;
4387
Joe Perchesb6b38f72010-04-21 03:50:45 +00004388 cFYI(1, "In FindNext");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004389
Steve French4b18f2a2008-04-29 00:06:05 +00004390 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004391 return -ENOENT;
4392
4393 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4394 (void **) &pSMBr);
4395 if (rc)
4396 return rc;
4397
Steve French50c2f752007-07-13 00:33:32 +00004398 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004399 byte_count = 0;
4400 pSMB->TotalDataCount = 0; /* no EAs */
4401 pSMB->MaxParameterCount = cpu_to_le16(8);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004402 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004403 pSMB->MaxSetupCount = 0;
4404 pSMB->Reserved = 0;
4405 pSMB->Flags = 0;
4406 pSMB->Timeout = 0;
4407 pSMB->Reserved2 = 0;
4408 pSMB->ParameterOffset = cpu_to_le16(
4409 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
4410 pSMB->DataCount = 0;
4411 pSMB->DataOffset = 0;
4412 pSMB->SetupCount = 1;
4413 pSMB->Reserved3 = 0;
4414 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
4415 pSMB->SearchHandle = searchHandle; /* always kept as le */
4416 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00004417 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004418 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4419 pSMB->ResumeKey = psrch_inf->resume_key;
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004420 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004421
4422 name_len = psrch_inf->resume_name_len;
4423 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00004424 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004425 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
4426 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07004427 /* 14 byte parm len above enough for 2 byte null terminator */
4428 pSMB->ResumeFileName[name_len] = 0;
4429 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004430 } else {
4431 rc = -EINVAL;
4432 goto FNext2_err_exit;
4433 }
4434 byte_count = params + 1 /* pad */ ;
4435 pSMB->TotalParameterCount = cpu_to_le16(params);
4436 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004437 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004438 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004439
Linus Torvalds1da177e2005-04-16 15:20:36 -07004440 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4441 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004442 cifs_stats_inc(&tcon->stats.cifs_stats.num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004443 if (rc) {
4444 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00004445 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07004446 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00004447 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004448 } else
Joe Perchesb6b38f72010-04-21 03:50:45 +00004449 cFYI(1, "FindNext returned = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004450 } else { /* decode response */
4451 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00004452
Steve French790fe572007-07-07 19:25:05 +00004453 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004454 unsigned int lnoff;
4455
Linus Torvalds1da177e2005-04-16 15:20:36 -07004456 /* BB fixme add lock for file (srch_info) struct here */
4457 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004458 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004459 else
Steve French4b18f2a2008-04-29 00:06:05 +00004460 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004461 response_data = (char *) &pSMBr->hdr.Protocol +
4462 le16_to_cpu(pSMBr->t2.ParameterOffset);
4463 parms = (T2_FNEXT_RSP_PARMS *)response_data;
4464 response_data = (char *)&pSMBr->hdr.Protocol +
4465 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00004466 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00004467 cifs_small_buf_release(
4468 psrch_inf->ntwrk_buf_start);
4469 else
4470 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004471 psrch_inf->srch_entries_start = response_data;
4472 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004473 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00004474 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004475 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004476 else
Steve French4b18f2a2008-04-29 00:06:05 +00004477 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00004478 psrch_inf->entries_in_buffer =
4479 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004480 psrch_inf->index_of_last_entry +=
4481 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004482 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004483 if (CIFSMaxBufSize < lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004484 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00004485 psrch_inf->last_entry = NULL;
4486 return rc;
4487 } else
4488 psrch_inf->last_entry =
4489 psrch_inf->srch_entries_start + lnoff;
4490
Joe Perchesb6b38f72010-04-21 03:50:45 +00004491/* cFYI(1, "fnxt2 entries in buf %d index_of_last %d",
4492 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004493
4494 /* BB fixme add unlock here */
4495 }
4496
4497 }
4498
4499 /* BB On error, should we leave previous search buf (and count and
4500 last entry fields) intact or free the previous one? */
4501
4502 /* Note: On -EAGAIN error only caller can retry on handle based calls
4503 since file handle passed in no longer valid */
4504FNext2_err_exit:
4505 if (rc != 0)
4506 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004507 return rc;
4508}
4509
4510int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004511CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004512 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004513{
4514 int rc = 0;
4515 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004516
Joe Perchesb6b38f72010-04-21 03:50:45 +00004517 cFYI(1, "In CIFSSMBFindClose");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004518 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
4519
4520 /* no sense returning error if session restarted
4521 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00004522 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004523 return 0;
4524 if (rc)
4525 return rc;
4526
Linus Torvalds1da177e2005-04-16 15:20:36 -07004527 pSMB->FileID = searchHandle;
4528 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04004529 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004530 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00004531 cERROR(1, "Send error in FindClose = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00004532
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004533 cifs_stats_inc(&tcon->stats.cifs_stats.num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004534
4535 /* Since session is dead, search handle closed on server already */
4536 if (rc == -EAGAIN)
4537 rc = 0;
4538
4539 return rc;
4540}
4541
Linus Torvalds1da177e2005-04-16 15:20:36 -07004542int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004543CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004544 const char *search_name, __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00004545 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004546{
4547 int rc = 0;
4548 TRANSACTION2_QPI_REQ *pSMB = NULL;
4549 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4550 int name_len, bytes_returned;
4551 __u16 params, byte_count;
4552
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004553 cFYI(1, "In GetSrvInodeNum for %s", search_name);
Steve French790fe572007-07-07 19:25:05 +00004554 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00004555 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004556
4557GetInodeNumberRetry:
4558 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004559 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004560 if (rc)
4561 return rc;
4562
Linus Torvalds1da177e2005-04-16 15:20:36 -07004563 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4564 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004565 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004566 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004567 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004568 name_len++; /* trailing null */
4569 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004570 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004571 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004572 name_len++; /* trailing null */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004573 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004574 }
4575
4576 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4577 pSMB->TotalDataCount = 0;
4578 pSMB->MaxParameterCount = cpu_to_le16(2);
4579 /* BB find exact max data count below from sess structure BB */
4580 pSMB->MaxDataCount = cpu_to_le16(4000);
4581 pSMB->MaxSetupCount = 0;
4582 pSMB->Reserved = 0;
4583 pSMB->Flags = 0;
4584 pSMB->Timeout = 0;
4585 pSMB->Reserved2 = 0;
4586 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004587 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004588 pSMB->DataCount = 0;
4589 pSMB->DataOffset = 0;
4590 pSMB->SetupCount = 1;
4591 pSMB->Reserved3 = 0;
4592 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4593 byte_count = params + 1 /* pad */ ;
4594 pSMB->TotalParameterCount = cpu_to_le16(params);
4595 pSMB->ParameterCount = pSMB->TotalParameterCount;
4596 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4597 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004598 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004599 pSMB->ByteCount = cpu_to_le16(byte_count);
4600
4601 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4602 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4603 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004604 cFYI(1, "error %d in QueryInternalInfo", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004605 } else {
4606 /* decode response */
4607 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004608 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04004609 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004610 /* If rc should we check for EOPNOSUPP and
4611 disable the srvino flag? or in caller? */
4612 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00004613 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004614 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4615 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00004616 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004617 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00004618 if (count < 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004619 cFYI(1, "Illegal size ret in QryIntrnlInf");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004620 rc = -EIO;
4621 goto GetInodeNumOut;
4622 }
4623 pfinfo = (struct file_internal_info *)
4624 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00004625 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004626 }
4627 }
4628GetInodeNumOut:
4629 cifs_buf_release(pSMB);
4630 if (rc == -EAGAIN)
4631 goto GetInodeNumberRetry;
4632 return rc;
4633}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004634
Igor Mammedovfec45852008-05-16 13:06:30 +04004635/* parses DFS refferal V3 structure
4636 * caller is responsible for freeing target_nodes
4637 * returns:
4638 * on success - 0
4639 * on failure - errno
4640 */
4641static int
Steve Frencha1fe78f2008-05-16 18:48:38 +00004642parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
Igor Mammedovfec45852008-05-16 13:06:30 +04004643 unsigned int *num_of_nodes,
4644 struct dfs_info3_param **target_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004645 const struct nls_table *nls_codepage, int remap,
4646 const char *searchName)
Igor Mammedovfec45852008-05-16 13:06:30 +04004647{
4648 int i, rc = 0;
4649 char *data_end;
4650 bool is_unicode;
4651 struct dfs_referral_level_3 *ref;
4652
Harvey Harrison5ca33c62008-07-23 17:45:58 -07004653 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4654 is_unicode = true;
4655 else
4656 is_unicode = false;
Igor Mammedovfec45852008-05-16 13:06:30 +04004657 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
4658
4659 if (*num_of_nodes < 1) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004660 cERROR(1, "num_referrals: must be at least > 0,"
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004661 "but we get num_referrals = %d", *num_of_nodes);
Igor Mammedovfec45852008-05-16 13:06:30 +04004662 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004663 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004664 }
4665
4666 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
Al Viro1d92cfd2008-06-02 10:59:02 +01004667 if (ref->VersionNumber != cpu_to_le16(3)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004668 cERROR(1, "Referrals of V%d version are not supported,"
4669 "should be V3", le16_to_cpu(ref->VersionNumber));
Igor Mammedovfec45852008-05-16 13:06:30 +04004670 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004671 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004672 }
4673
4674 /* get the upper boundary of the resp buffer */
4675 data_end = (char *)(&(pSMBr->PathConsumed)) +
4676 le16_to_cpu(pSMBr->t2.DataCount);
4677
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004678 cFYI(1, "num_referrals: %d dfs flags: 0x%x ...",
Igor Mammedovfec45852008-05-16 13:06:30 +04004679 *num_of_nodes,
Joe Perchesb6b38f72010-04-21 03:50:45 +00004680 le32_to_cpu(pSMBr->DFSFlags));
Igor Mammedovfec45852008-05-16 13:06:30 +04004681
4682 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
4683 *num_of_nodes, GFP_KERNEL);
4684 if (*target_nodes == NULL) {
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004685 cERROR(1, "Failed to allocate buffer for target_nodes");
Igor Mammedovfec45852008-05-16 13:06:30 +04004686 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004687 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004688 }
4689
Daniel Mack3ad2f3f2010-02-03 08:01:28 +08004690 /* collect necessary data from referrals */
Igor Mammedovfec45852008-05-16 13:06:30 +04004691 for (i = 0; i < *num_of_nodes; i++) {
4692 char *temp;
4693 int max_len;
4694 struct dfs_info3_param *node = (*target_nodes)+i;
4695
Steve French0e0d2cf2009-05-01 05:27:32 +00004696 node->flags = le32_to_cpu(pSMBr->DFSFlags);
Igor Mammedov2c556082008-10-23 13:58:42 +04004697 if (is_unicode) {
Jeff Layton331c3132008-12-17 06:31:53 -05004698 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4699 GFP_KERNEL);
Steve French2920ee22009-08-31 15:27:26 +00004700 if (tmp == NULL) {
4701 rc = -ENOMEM;
4702 goto parse_DFS_referrals_exit;
4703 }
Steve Frenchacbbb762012-01-18 22:32:33 -06004704 cifsConvertToUTF16((__le16 *) tmp, searchName,
4705 PATH_MAX, nls_codepage, remap);
4706 node->path_consumed = cifs_utf16_bytes(tmp,
Jeff Layton69f801f2009-04-30 06:46:32 -04004707 le16_to_cpu(pSMBr->PathConsumed),
Igor Mammedov2c556082008-10-23 13:58:42 +04004708 nls_codepage);
4709 kfree(tmp);
4710 } else
4711 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4712
Igor Mammedovfec45852008-05-16 13:06:30 +04004713 node->server_type = le16_to_cpu(ref->ServerType);
4714 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4715
4716 /* copy DfsPath */
4717 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4718 max_len = data_end - temp;
Steve Frenchacbbb762012-01-18 22:32:33 -06004719 node->path_name = cifs_strndup_from_utf16(temp, max_len,
4720 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004721 if (!node->path_name) {
4722 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004723 goto parse_DFS_referrals_exit;
Jeff Layton066ce682009-04-30 07:16:14 -04004724 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004725
4726 /* copy link target UNC */
4727 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4728 max_len = data_end - temp;
Steve Frenchacbbb762012-01-18 22:32:33 -06004729 node->node_name = cifs_strndup_from_utf16(temp, max_len,
4730 is_unicode, nls_codepage);
Stefan Metzmacherd8f27992012-05-04 00:19:28 +02004731 if (!node->node_name) {
Jeff Laytond8e2f532009-05-14 07:46:59 -04004732 rc = -ENOMEM;
Stefan Metzmacherd8f27992012-05-04 00:19:28 +02004733 goto parse_DFS_referrals_exit;
4734 }
4735
4736 ref++;
Igor Mammedovfec45852008-05-16 13:06:30 +04004737 }
4738
Steve Frencha1fe78f2008-05-16 18:48:38 +00004739parse_DFS_referrals_exit:
Igor Mammedovfec45852008-05-16 13:06:30 +04004740 if (rc) {
4741 free_dfs_info_array(*target_nodes, *num_of_nodes);
4742 *target_nodes = NULL;
4743 *num_of_nodes = 0;
4744 }
4745 return rc;
4746}
4747
Linus Torvalds1da177e2005-04-16 15:20:36 -07004748int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004749CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004750 const char *search_name, struct dfs_info3_param **target_nodes,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004751 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004752 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004753{
4754/* TRANS2_GET_DFS_REFERRAL */
4755 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4756 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004757 int rc = 0;
4758 int bytes_returned;
4759 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004760 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004761 *num_of_nodes = 0;
4762 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004763
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004764 cFYI(1, "In GetDFSRefer the path %s", search_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004765 if (ses == NULL)
4766 return -ENODEV;
4767getDFSRetry:
4768 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4769 (void **) &pSMBr);
4770 if (rc)
4771 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004772
4773 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004774 but should never be null here anyway */
Pavel Shilovsky88257362012-05-23 14:01:59 +04004775 pSMB->hdr.Mid = get_next_mid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004776 pSMB->hdr.Tid = ses->ipc_tid;
4777 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004778 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004779 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004780 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004781 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004782
4783 if (ses->capabilities & CAP_UNICODE) {
4784 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4785 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004786 cifsConvertToUTF16((__le16 *) pSMB->RequestFileName,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004787 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004788 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004789 name_len++; /* trailing null */
4790 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004791 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004792 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004793 name_len++; /* trailing null */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004794 strncpy(pSMB->RequestFileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004795 }
4796
Steve French790fe572007-07-07 19:25:05 +00004797 if (ses->server) {
Steve French96daf2b2011-05-27 04:34:02 +00004798 if (ses->server->sec_mode &
Steve French1a4e15a2006-10-12 21:33:51 +00004799 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4800 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4801 }
4802
Steve French50c2f752007-07-13 00:33:32 +00004803 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004804
Linus Torvalds1da177e2005-04-16 15:20:36 -07004805 params = 2 /* level */ + name_len /*includes null */ ;
4806 pSMB->TotalDataCount = 0;
4807 pSMB->DataCount = 0;
4808 pSMB->DataOffset = 0;
4809 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004810 /* BB find exact max SMB PDU from sess structure BB */
4811 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004812 pSMB->MaxSetupCount = 0;
4813 pSMB->Reserved = 0;
4814 pSMB->Flags = 0;
4815 pSMB->Timeout = 0;
4816 pSMB->Reserved2 = 0;
4817 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004818 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004819 pSMB->SetupCount = 1;
4820 pSMB->Reserved3 = 0;
4821 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4822 byte_count = params + 3 /* pad */ ;
4823 pSMB->ParameterCount = cpu_to_le16(params);
4824 pSMB->TotalParameterCount = pSMB->ParameterCount;
4825 pSMB->MaxReferralLevel = cpu_to_le16(3);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004826 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004827 pSMB->ByteCount = cpu_to_le16(byte_count);
4828
4829 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4830 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4831 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004832 cFYI(1, "Send error in GetDFSRefer = %d", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004833 goto GetDFSRefExit;
4834 }
4835 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004836
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004837 /* BB Also check if enough total bytes returned? */
Jeff Layton820a8032011-05-04 08:05:26 -04004838 if (rc || get_bcc(&pSMBr->hdr) < 17) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004839 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004840 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004841 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004842
Joe Perchesb6b38f72010-04-21 03:50:45 +00004843 cFYI(1, "Decoding GetDFSRefer response BCC: %d Offset %d",
Jeff Layton820a8032011-05-04 08:05:26 -04004844 get_bcc(&pSMBr->hdr),
Joe Perchesb6b38f72010-04-21 03:50:45 +00004845 le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04004846
4847 /* parse returned result into more usable form */
Steve Frencha1fe78f2008-05-16 18:48:38 +00004848 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004849 target_nodes, nls_codepage, remap,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004850 search_name);
Igor Mammedovfec45852008-05-16 13:06:30 +04004851
Linus Torvalds1da177e2005-04-16 15:20:36 -07004852GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004853 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004854
4855 if (rc == -EAGAIN)
4856 goto getDFSRetry;
4857
4858 return rc;
4859}
4860
Steve French20962432005-09-21 22:05:57 -07004861/* Query File System Info such as free space to old servers such as Win 9x */
4862int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004863SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4864 struct kstatfs *FSData)
Steve French20962432005-09-21 22:05:57 -07004865{
4866/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4867 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4868 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4869 FILE_SYSTEM_ALLOC_INFO *response_data;
4870 int rc = 0;
4871 int bytes_returned = 0;
4872 __u16 params, byte_count;
4873
Joe Perchesb6b38f72010-04-21 03:50:45 +00004874 cFYI(1, "OldQFSInfo");
Steve French20962432005-09-21 22:05:57 -07004875oldQFSInfoRetry:
4876 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4877 (void **) &pSMBr);
4878 if (rc)
4879 return rc;
Steve French20962432005-09-21 22:05:57 -07004880
4881 params = 2; /* level */
4882 pSMB->TotalDataCount = 0;
4883 pSMB->MaxParameterCount = cpu_to_le16(2);
4884 pSMB->MaxDataCount = cpu_to_le16(1000);
4885 pSMB->MaxSetupCount = 0;
4886 pSMB->Reserved = 0;
4887 pSMB->Flags = 0;
4888 pSMB->Timeout = 0;
4889 pSMB->Reserved2 = 0;
4890 byte_count = params + 1 /* pad */ ;
4891 pSMB->TotalParameterCount = cpu_to_le16(params);
4892 pSMB->ParameterCount = pSMB->TotalParameterCount;
4893 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4894 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4895 pSMB->DataCount = 0;
4896 pSMB->DataOffset = 0;
4897 pSMB->SetupCount = 1;
4898 pSMB->Reserved3 = 0;
4899 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4900 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004901 inc_rfc1001_len(pSMB, byte_count);
Steve French20962432005-09-21 22:05:57 -07004902 pSMB->ByteCount = cpu_to_le16(byte_count);
4903
4904 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4905 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4906 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004907 cFYI(1, "Send error in QFSInfo = %d", rc);
Steve French20962432005-09-21 22:05:57 -07004908 } else { /* decode response */
4909 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4910
Jeff Layton820a8032011-05-04 08:05:26 -04004911 if (rc || get_bcc(&pSMBr->hdr) < 18)
Steve French20962432005-09-21 22:05:57 -07004912 rc = -EIO; /* bad smb */
4913 else {
4914 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004915 cFYI(1, "qfsinf resp BCC: %d Offset %d",
Jeff Layton820a8032011-05-04 08:05:26 -04004916 get_bcc(&pSMBr->hdr), data_offset);
Steve French20962432005-09-21 22:05:57 -07004917
Steve French50c2f752007-07-13 00:33:32 +00004918 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004919 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4920 FSData->f_bsize =
4921 le16_to_cpu(response_data->BytesPerSector) *
4922 le32_to_cpu(response_data->
4923 SectorsPerAllocationUnit);
4924 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004925 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004926 FSData->f_bfree = FSData->f_bavail =
4927 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004928 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
4929 (unsigned long long)FSData->f_blocks,
4930 (unsigned long long)FSData->f_bfree,
4931 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07004932 }
4933 }
4934 cifs_buf_release(pSMB);
4935
4936 if (rc == -EAGAIN)
4937 goto oldQFSInfoRetry;
4938
4939 return rc;
4940}
4941
Linus Torvalds1da177e2005-04-16 15:20:36 -07004942int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004943CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4944 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004945{
4946/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4947 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4948 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4949 FILE_SYSTEM_INFO *response_data;
4950 int rc = 0;
4951 int bytes_returned = 0;
4952 __u16 params, byte_count;
4953
Joe Perchesb6b38f72010-04-21 03:50:45 +00004954 cFYI(1, "In QFSInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004955QFSInfoRetry:
4956 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4957 (void **) &pSMBr);
4958 if (rc)
4959 return rc;
4960
4961 params = 2; /* level */
4962 pSMB->TotalDataCount = 0;
4963 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004964 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004965 pSMB->MaxSetupCount = 0;
4966 pSMB->Reserved = 0;
4967 pSMB->Flags = 0;
4968 pSMB->Timeout = 0;
4969 pSMB->Reserved2 = 0;
4970 byte_count = params + 1 /* pad */ ;
4971 pSMB->TotalParameterCount = cpu_to_le16(params);
4972 pSMB->ParameterCount = pSMB->TotalParameterCount;
4973 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004974 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004975 pSMB->DataCount = 0;
4976 pSMB->DataOffset = 0;
4977 pSMB->SetupCount = 1;
4978 pSMB->Reserved3 = 0;
4979 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4980 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004981 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004982 pSMB->ByteCount = cpu_to_le16(byte_count);
4983
4984 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4985 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4986 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004987 cFYI(1, "Send error in QFSInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004988 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00004989 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004990
Jeff Layton820a8032011-05-04 08:05:26 -04004991 if (rc || get_bcc(&pSMBr->hdr) < 24)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004992 rc = -EIO; /* bad smb */
4993 else {
4994 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004995
4996 response_data =
4997 (FILE_SYSTEM_INFO
4998 *) (((char *) &pSMBr->hdr.Protocol) +
4999 data_offset);
5000 FSData->f_bsize =
5001 le32_to_cpu(response_data->BytesPerSector) *
5002 le32_to_cpu(response_data->
5003 SectorsPerAllocationUnit);
5004 FSData->f_blocks =
5005 le64_to_cpu(response_data->TotalAllocationUnits);
5006 FSData->f_bfree = FSData->f_bavail =
5007 le64_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesb6b38f72010-04-21 03:50:45 +00005008 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
5009 (unsigned long long)FSData->f_blocks,
5010 (unsigned long long)FSData->f_bfree,
5011 FSData->f_bsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005012 }
5013 }
5014 cifs_buf_release(pSMB);
5015
5016 if (rc == -EAGAIN)
5017 goto QFSInfoRetry;
5018
5019 return rc;
5020}
5021
5022int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005023CIFSSMBQFSAttributeInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005024{
5025/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
5026 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5027 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5028 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
5029 int rc = 0;
5030 int bytes_returned = 0;
5031 __u16 params, byte_count;
5032
Joe Perchesb6b38f72010-04-21 03:50:45 +00005033 cFYI(1, "In QFSAttributeInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005034QFSAttributeRetry:
5035 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5036 (void **) &pSMBr);
5037 if (rc)
5038 return rc;
5039
5040 params = 2; /* level */
5041 pSMB->TotalDataCount = 0;
5042 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005043 /* BB find exact max SMB PDU from sess structure BB */
5044 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005045 pSMB->MaxSetupCount = 0;
5046 pSMB->Reserved = 0;
5047 pSMB->Flags = 0;
5048 pSMB->Timeout = 0;
5049 pSMB->Reserved2 = 0;
5050 byte_count = params + 1 /* pad */ ;
5051 pSMB->TotalParameterCount = cpu_to_le16(params);
5052 pSMB->ParameterCount = pSMB->TotalParameterCount;
5053 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005054 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005055 pSMB->DataCount = 0;
5056 pSMB->DataOffset = 0;
5057 pSMB->SetupCount = 1;
5058 pSMB->Reserved3 = 0;
5059 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5060 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005061 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005062 pSMB->ByteCount = cpu_to_le16(byte_count);
5063
5064 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5065 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5066 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005067 cERROR(1, "Send error in QFSAttributeInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005068 } else { /* decode response */
5069 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5070
Jeff Layton820a8032011-05-04 08:05:26 -04005071 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Steve French50c2f752007-07-13 00:33:32 +00005072 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005073 rc = -EIO; /* bad smb */
5074 } else {
5075 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5076 response_data =
5077 (FILE_SYSTEM_ATTRIBUTE_INFO
5078 *) (((char *) &pSMBr->hdr.Protocol) +
5079 data_offset);
5080 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005081 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005082 }
5083 }
5084 cifs_buf_release(pSMB);
5085
5086 if (rc == -EAGAIN)
5087 goto QFSAttributeRetry;
5088
5089 return rc;
5090}
5091
5092int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005093CIFSSMBQFSDeviceInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005094{
5095/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
5096 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5097 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5098 FILE_SYSTEM_DEVICE_INFO *response_data;
5099 int rc = 0;
5100 int bytes_returned = 0;
5101 __u16 params, byte_count;
5102
Joe Perchesb6b38f72010-04-21 03:50:45 +00005103 cFYI(1, "In QFSDeviceInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005104QFSDeviceRetry:
5105 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5106 (void **) &pSMBr);
5107 if (rc)
5108 return rc;
5109
5110 params = 2; /* level */
5111 pSMB->TotalDataCount = 0;
5112 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005113 /* BB find exact max SMB PDU from sess structure BB */
5114 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005115 pSMB->MaxSetupCount = 0;
5116 pSMB->Reserved = 0;
5117 pSMB->Flags = 0;
5118 pSMB->Timeout = 0;
5119 pSMB->Reserved2 = 0;
5120 byte_count = params + 1 /* pad */ ;
5121 pSMB->TotalParameterCount = cpu_to_le16(params);
5122 pSMB->ParameterCount = pSMB->TotalParameterCount;
5123 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005124 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005125
5126 pSMB->DataCount = 0;
5127 pSMB->DataOffset = 0;
5128 pSMB->SetupCount = 1;
5129 pSMB->Reserved3 = 0;
5130 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5131 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005132 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005133 pSMB->ByteCount = cpu_to_le16(byte_count);
5134
5135 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5136 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5137 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005138 cFYI(1, "Send error in QFSDeviceInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005139 } else { /* decode response */
5140 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5141
Jeff Layton820a8032011-05-04 08:05:26 -04005142 if (rc || get_bcc(&pSMBr->hdr) <
5143 sizeof(FILE_SYSTEM_DEVICE_INFO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005144 rc = -EIO; /* bad smb */
5145 else {
5146 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5147 response_data =
Steve French737b7582005-04-28 22:41:06 -07005148 (FILE_SYSTEM_DEVICE_INFO *)
5149 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07005150 data_offset);
5151 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005152 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005153 }
5154 }
5155 cifs_buf_release(pSMB);
5156
5157 if (rc == -EAGAIN)
5158 goto QFSDeviceRetry;
5159
5160 return rc;
5161}
5162
5163int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005164CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005165{
5166/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
5167 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5168 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5169 FILE_SYSTEM_UNIX_INFO *response_data;
5170 int rc = 0;
5171 int bytes_returned = 0;
5172 __u16 params, byte_count;
5173
Joe Perchesb6b38f72010-04-21 03:50:45 +00005174 cFYI(1, "In QFSUnixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005175QFSUnixRetry:
Jeff Laytonf5695992010-09-29 15:27:08 -04005176 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5177 (void **) &pSMB, (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005178 if (rc)
5179 return rc;
5180
5181 params = 2; /* level */
5182 pSMB->TotalDataCount = 0;
5183 pSMB->DataCount = 0;
5184 pSMB->DataOffset = 0;
5185 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005186 /* BB find exact max SMB PDU from sess structure BB */
5187 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005188 pSMB->MaxSetupCount = 0;
5189 pSMB->Reserved = 0;
5190 pSMB->Flags = 0;
5191 pSMB->Timeout = 0;
5192 pSMB->Reserved2 = 0;
5193 byte_count = params + 1 /* pad */ ;
5194 pSMB->ParameterCount = cpu_to_le16(params);
5195 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005196 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5197 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005198 pSMB->SetupCount = 1;
5199 pSMB->Reserved3 = 0;
5200 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5201 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005202 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005203 pSMB->ByteCount = cpu_to_le16(byte_count);
5204
5205 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5206 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5207 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005208 cERROR(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005209 } else { /* decode response */
5210 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5211
Jeff Layton820a8032011-05-04 08:05:26 -04005212 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005213 rc = -EIO; /* bad smb */
5214 } else {
5215 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5216 response_data =
5217 (FILE_SYSTEM_UNIX_INFO
5218 *) (((char *) &pSMBr->hdr.Protocol) +
5219 data_offset);
5220 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005221 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005222 }
5223 }
5224 cifs_buf_release(pSMB);
5225
5226 if (rc == -EAGAIN)
5227 goto QFSUnixRetry;
5228
5229
5230 return rc;
5231}
5232
Jeremy Allisonac670552005-06-22 17:26:35 -07005233int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005234CIFSSMBSetFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07005235{
5236/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
5237 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
5238 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
5239 int rc = 0;
5240 int bytes_returned = 0;
5241 __u16 params, param_offset, offset, byte_count;
5242
Joe Perchesb6b38f72010-04-21 03:50:45 +00005243 cFYI(1, "In SETFSUnixInfo");
Jeremy Allisonac670552005-06-22 17:26:35 -07005244SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00005245 /* BB switch to small buf init to save memory */
Jeff Laytonf5695992010-09-29 15:27:08 -04005246 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5247 (void **) &pSMB, (void **) &pSMBr);
Jeremy Allisonac670552005-06-22 17:26:35 -07005248 if (rc)
5249 return rc;
5250
5251 params = 4; /* 2 bytes zero followed by info level. */
5252 pSMB->MaxSetupCount = 0;
5253 pSMB->Reserved = 0;
5254 pSMB->Flags = 0;
5255 pSMB->Timeout = 0;
5256 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00005257 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
5258 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07005259 offset = param_offset + params;
5260
5261 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00005262 /* BB find exact max SMB PDU from sess structure BB */
5263 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07005264 pSMB->SetupCount = 1;
5265 pSMB->Reserved3 = 0;
5266 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
5267 byte_count = 1 /* pad */ + params + 12;
5268
5269 pSMB->DataCount = cpu_to_le16(12);
5270 pSMB->ParameterCount = cpu_to_le16(params);
5271 pSMB->TotalDataCount = pSMB->DataCount;
5272 pSMB->TotalParameterCount = pSMB->ParameterCount;
5273 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5274 pSMB->DataOffset = cpu_to_le16(offset);
5275
5276 /* Params. */
5277 pSMB->FileNum = 0;
5278 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
5279
5280 /* Data. */
5281 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
5282 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
5283 pSMB->ClientUnixCap = cpu_to_le64(cap);
5284
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005285 inc_rfc1001_len(pSMB, byte_count);
Jeremy Allisonac670552005-06-22 17:26:35 -07005286 pSMB->ByteCount = cpu_to_le16(byte_count);
5287
5288 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5289 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5290 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005291 cERROR(1, "Send error in SETFSUnixInfo = %d", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07005292 } else { /* decode response */
5293 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00005294 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07005295 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07005296 }
5297 cifs_buf_release(pSMB);
5298
5299 if (rc == -EAGAIN)
5300 goto SETFSUnixRetry;
5301
5302 return rc;
5303}
5304
5305
Linus Torvalds1da177e2005-04-16 15:20:36 -07005306
5307int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005308CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon,
Steve French737b7582005-04-28 22:41:06 -07005309 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005310{
5311/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
5312 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5313 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5314 FILE_SYSTEM_POSIX_INFO *response_data;
5315 int rc = 0;
5316 int bytes_returned = 0;
5317 __u16 params, byte_count;
5318
Joe Perchesb6b38f72010-04-21 03:50:45 +00005319 cFYI(1, "In QFSPosixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005320QFSPosixRetry:
5321 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5322 (void **) &pSMBr);
5323 if (rc)
5324 return rc;
5325
5326 params = 2; /* level */
5327 pSMB->TotalDataCount = 0;
5328 pSMB->DataCount = 0;
5329 pSMB->DataOffset = 0;
5330 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005331 /* BB find exact max SMB PDU from sess structure BB */
5332 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005333 pSMB->MaxSetupCount = 0;
5334 pSMB->Reserved = 0;
5335 pSMB->Flags = 0;
5336 pSMB->Timeout = 0;
5337 pSMB->Reserved2 = 0;
5338 byte_count = params + 1 /* pad */ ;
5339 pSMB->ParameterCount = cpu_to_le16(params);
5340 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005341 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5342 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005343 pSMB->SetupCount = 1;
5344 pSMB->Reserved3 = 0;
5345 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5346 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005347 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005348 pSMB->ByteCount = cpu_to_le16(byte_count);
5349
5350 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5351 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5352 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005353 cFYI(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005354 } else { /* decode response */
5355 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5356
Jeff Layton820a8032011-05-04 08:05:26 -04005357 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005358 rc = -EIO; /* bad smb */
5359 } else {
5360 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5361 response_data =
5362 (FILE_SYSTEM_POSIX_INFO
5363 *) (((char *) &pSMBr->hdr.Protocol) +
5364 data_offset);
5365 FSData->f_bsize =
5366 le32_to_cpu(response_data->BlockSize);
5367 FSData->f_blocks =
5368 le64_to_cpu(response_data->TotalBlocks);
5369 FSData->f_bfree =
5370 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00005371 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005372 FSData->f_bavail = FSData->f_bfree;
5373 } else {
5374 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00005375 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005376 }
Steve French790fe572007-07-07 19:25:05 +00005377 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005378 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00005379 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00005380 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005381 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00005382 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005383 }
5384 }
5385 cifs_buf_release(pSMB);
5386
5387 if (rc == -EAGAIN)
5388 goto QFSPosixRetry;
5389
5390 return rc;
5391}
5392
5393
Steve French50c2f752007-07-13 00:33:32 +00005394/* We can not use write of zero bytes trick to
5395 set file size due to need for large file support. Also note that
5396 this SetPathInfo is preferred to SetFileInfo based method in next
Linus Torvalds1da177e2005-04-16 15:20:36 -07005397 routine which is only needed to work around a sharing violation bug
5398 in Samba which this routine can run into */
5399
5400int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005401CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
5402 const char *fileName, __u64 size, bool SetAllocation,
Steve French737b7582005-04-28 22:41:06 -07005403 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005404{
5405 struct smb_com_transaction2_spi_req *pSMB = NULL;
5406 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5407 struct file_end_of_file_info *parm_data;
5408 int name_len;
5409 int rc = 0;
5410 int bytes_returned = 0;
5411 __u16 params, byte_count, data_count, param_offset, offset;
5412
Joe Perchesb6b38f72010-04-21 03:50:45 +00005413 cFYI(1, "In SetEOF");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005414SetEOFRetry:
5415 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5416 (void **) &pSMBr);
5417 if (rc)
5418 return rc;
5419
5420 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5421 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005422 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5423 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005424 name_len++; /* trailing null */
5425 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005426 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005427 name_len = strnlen(fileName, PATH_MAX);
5428 name_len++; /* trailing null */
5429 strncpy(pSMB->FileName, fileName, name_len);
5430 }
5431 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005432 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005433 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07005434 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005435 pSMB->MaxSetupCount = 0;
5436 pSMB->Reserved = 0;
5437 pSMB->Flags = 0;
5438 pSMB->Timeout = 0;
5439 pSMB->Reserved2 = 0;
5440 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005441 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005442 offset = param_offset + params;
Steve French790fe572007-07-07 19:25:05 +00005443 if (SetAllocation) {
Steve French50c2f752007-07-13 00:33:32 +00005444 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5445 pSMB->InformationLevel =
5446 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5447 else
5448 pSMB->InformationLevel =
5449 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5450 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005451 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5452 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005453 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005454 else
5455 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005456 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005457 }
5458
5459 parm_data =
5460 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
5461 offset);
5462 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5463 pSMB->DataOffset = cpu_to_le16(offset);
5464 pSMB->SetupCount = 1;
5465 pSMB->Reserved3 = 0;
5466 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5467 byte_count = 3 /* pad */ + params + data_count;
5468 pSMB->DataCount = cpu_to_le16(data_count);
5469 pSMB->TotalDataCount = pSMB->DataCount;
5470 pSMB->ParameterCount = cpu_to_le16(params);
5471 pSMB->TotalParameterCount = pSMB->ParameterCount;
5472 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005473 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005474 parm_data->FileSize = cpu_to_le64(size);
5475 pSMB->ByteCount = cpu_to_le16(byte_count);
5476 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5477 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005478 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005479 cFYI(1, "SetPathInfo (file size) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005480
5481 cifs_buf_release(pSMB);
5482
5483 if (rc == -EAGAIN)
5484 goto SetEOFRetry;
5485
5486 return rc;
5487}
5488
5489int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005490CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon, __u64 size,
Steve French4b18f2a2008-04-29 00:06:05 +00005491 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005492{
5493 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005494 struct file_end_of_file_info *parm_data;
5495 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005496 __u16 params, param_offset, offset, byte_count, count;
5497
Joe Perchesb6b38f72010-04-21 03:50:45 +00005498 cFYI(1, "SetFileSize (via SetFileInfo) %lld",
5499 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07005500 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5501
Linus Torvalds1da177e2005-04-16 15:20:36 -07005502 if (rc)
5503 return rc;
5504
5505 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5506 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005507
Linus Torvalds1da177e2005-04-16 15:20:36 -07005508 params = 6;
5509 pSMB->MaxSetupCount = 0;
5510 pSMB->Reserved = 0;
5511 pSMB->Flags = 0;
5512 pSMB->Timeout = 0;
5513 pSMB->Reserved2 = 0;
5514 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5515 offset = param_offset + params;
5516
Linus Torvalds1da177e2005-04-16 15:20:36 -07005517 count = sizeof(struct file_end_of_file_info);
5518 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005519 /* BB find exact max SMB PDU from sess structure BB */
5520 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005521 pSMB->SetupCount = 1;
5522 pSMB->Reserved3 = 0;
5523 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5524 byte_count = 3 /* pad */ + params + count;
5525 pSMB->DataCount = cpu_to_le16(count);
5526 pSMB->ParameterCount = cpu_to_le16(params);
5527 pSMB->TotalDataCount = pSMB->DataCount;
5528 pSMB->TotalParameterCount = pSMB->ParameterCount;
5529 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5530 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00005531 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
5532 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005533 pSMB->DataOffset = cpu_to_le16(offset);
5534 parm_data->FileSize = cpu_to_le64(size);
5535 pSMB->Fid = fid;
Steve French790fe572007-07-07 19:25:05 +00005536 if (SetAllocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005537 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5538 pSMB->InformationLevel =
5539 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5540 else
5541 pSMB->InformationLevel =
5542 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00005543 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005544 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5545 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005546 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005547 else
5548 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005549 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005550 }
5551 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005552 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005553 pSMB->ByteCount = cpu_to_le16(byte_count);
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005554 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005555 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005556 cFYI(1, "Send error in SetFileInfo (SetFileSize) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005557 }
5558
Steve French50c2f752007-07-13 00:33:32 +00005559 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005560 since file handle passed in no longer valid */
5561
5562 return rc;
5563}
5564
Steve French50c2f752007-07-13 00:33:32 +00005565/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07005566 an open handle, rather than by pathname - this is awkward due to
5567 potential access conflicts on the open, but it is unavoidable for these
5568 old servers since the only other choice is to go from 100 nanosecond DCE
5569 time and resort to the original setpathinfo level which takes the ancient
5570 DOS time format with 2 second granularity */
5571int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005572CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005573 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005574{
5575 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005576 char *data_offset;
5577 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005578 __u16 params, param_offset, offset, byte_count, count;
5579
Joe Perchesb6b38f72010-04-21 03:50:45 +00005580 cFYI(1, "Set Times (via SetFileInfo)");
Steve Frenchcd634992005-04-28 22:41:10 -07005581 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5582
Linus Torvalds1da177e2005-04-16 15:20:36 -07005583 if (rc)
5584 return rc;
5585
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005586 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5587 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005588
Linus Torvalds1da177e2005-04-16 15:20:36 -07005589 params = 6;
5590 pSMB->MaxSetupCount = 0;
5591 pSMB->Reserved = 0;
5592 pSMB->Flags = 0;
5593 pSMB->Timeout = 0;
5594 pSMB->Reserved2 = 0;
5595 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5596 offset = param_offset + params;
5597
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005598 data_offset = (char *)pSMB +
5599 offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005600
Steve French26f57362007-08-30 22:09:15 +00005601 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005602 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005603 /* BB find max SMB PDU from sess */
5604 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005605 pSMB->SetupCount = 1;
5606 pSMB->Reserved3 = 0;
5607 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5608 byte_count = 3 /* pad */ + params + count;
5609 pSMB->DataCount = cpu_to_le16(count);
5610 pSMB->ParameterCount = cpu_to_le16(params);
5611 pSMB->TotalDataCount = pSMB->DataCount;
5612 pSMB->TotalParameterCount = pSMB->ParameterCount;
5613 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5614 pSMB->DataOffset = cpu_to_le16(offset);
5615 pSMB->Fid = fid;
5616 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5617 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5618 else
5619 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5620 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005621 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005622 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005623 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005624 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005625 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005626 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005627
Steve French50c2f752007-07-13 00:33:32 +00005628 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005629 since file handle passed in no longer valid */
5630
5631 return rc;
5632}
5633
Jeff Layton6d22f092008-09-23 11:48:35 -04005634int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005635CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6d22f092008-09-23 11:48:35 -04005636 bool delete_file, __u16 fid, __u32 pid_of_opener)
5637{
5638 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5639 char *data_offset;
5640 int rc = 0;
5641 __u16 params, param_offset, offset, byte_count, count;
5642
Joe Perchesb6b38f72010-04-21 03:50:45 +00005643 cFYI(1, "Set File Disposition (via SetFileInfo)");
Jeff Layton6d22f092008-09-23 11:48:35 -04005644 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5645
5646 if (rc)
5647 return rc;
5648
5649 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5650 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5651
5652 params = 6;
5653 pSMB->MaxSetupCount = 0;
5654 pSMB->Reserved = 0;
5655 pSMB->Flags = 0;
5656 pSMB->Timeout = 0;
5657 pSMB->Reserved2 = 0;
5658 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5659 offset = param_offset + params;
5660
5661 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5662
5663 count = 1;
5664 pSMB->MaxParameterCount = cpu_to_le16(2);
5665 /* BB find max SMB PDU from sess */
5666 pSMB->MaxDataCount = cpu_to_le16(1000);
5667 pSMB->SetupCount = 1;
5668 pSMB->Reserved3 = 0;
5669 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5670 byte_count = 3 /* pad */ + params + count;
5671 pSMB->DataCount = cpu_to_le16(count);
5672 pSMB->ParameterCount = cpu_to_le16(params);
5673 pSMB->TotalDataCount = pSMB->DataCount;
5674 pSMB->TotalParameterCount = pSMB->ParameterCount;
5675 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5676 pSMB->DataOffset = cpu_to_le16(offset);
5677 pSMB->Fid = fid;
5678 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5679 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005680 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton6d22f092008-09-23 11:48:35 -04005681 pSMB->ByteCount = cpu_to_le16(byte_count);
5682 *data_offset = delete_file ? 1 : 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005683 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Jeff Layton6d22f092008-09-23 11:48:35 -04005684 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005685 cFYI(1, "Send error in SetFileDisposition = %d", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005686
5687 return rc;
5688}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005689
5690int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005691CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6fc000e2008-08-02 07:26:12 -04005692 const char *fileName, const FILE_BASIC_INFO *data,
5693 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005694{
5695 TRANSACTION2_SPI_REQ *pSMB = NULL;
5696 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5697 int name_len;
5698 int rc = 0;
5699 int bytes_returned = 0;
5700 char *data_offset;
5701 __u16 params, param_offset, offset, byte_count, count;
5702
Joe Perchesb6b38f72010-04-21 03:50:45 +00005703 cFYI(1, "In SetTimes");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005704
5705SetTimesRetry:
5706 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5707 (void **) &pSMBr);
5708 if (rc)
5709 return rc;
5710
5711 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5712 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005713 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5714 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005715 name_len++; /* trailing null */
5716 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005717 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005718 name_len = strnlen(fileName, PATH_MAX);
5719 name_len++; /* trailing null */
5720 strncpy(pSMB->FileName, fileName, name_len);
5721 }
5722
5723 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005724 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005725 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005726 /* BB find max SMB PDU from sess structure BB */
5727 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005728 pSMB->MaxSetupCount = 0;
5729 pSMB->Reserved = 0;
5730 pSMB->Flags = 0;
5731 pSMB->Timeout = 0;
5732 pSMB->Reserved2 = 0;
5733 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005734 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005735 offset = param_offset + params;
5736 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5737 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5738 pSMB->DataOffset = cpu_to_le16(offset);
5739 pSMB->SetupCount = 1;
5740 pSMB->Reserved3 = 0;
5741 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5742 byte_count = 3 /* pad */ + params + count;
5743
5744 pSMB->DataCount = cpu_to_le16(count);
5745 pSMB->ParameterCount = cpu_to_le16(params);
5746 pSMB->TotalDataCount = pSMB->DataCount;
5747 pSMB->TotalParameterCount = pSMB->ParameterCount;
5748 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5749 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5750 else
5751 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5752 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005753 inc_rfc1001_len(pSMB, byte_count);
Steve French26f57362007-08-30 22:09:15 +00005754 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005755 pSMB->ByteCount = cpu_to_le16(byte_count);
5756 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5757 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005758 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005759 cFYI(1, "SetPathInfo (times) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005760
5761 cifs_buf_release(pSMB);
5762
5763 if (rc == -EAGAIN)
5764 goto SetTimesRetry;
5765
5766 return rc;
5767}
5768
5769/* Can not be used to set time stamps yet (due to old DOS time format) */
5770/* Can be used to set attributes */
5771#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5772 handling it anyway and NT4 was what we thought it would be needed for
5773 Do not delete it until we prove whether needed for Win9x though */
5774int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005775CIFSSMBSetAttrLegacy(unsigned int xid, struct cifs_tcon *tcon, char *fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005776 __u16 dos_attrs, const struct nls_table *nls_codepage)
5777{
5778 SETATTR_REQ *pSMB = NULL;
5779 SETATTR_RSP *pSMBr = NULL;
5780 int rc = 0;
5781 int bytes_returned;
5782 int name_len;
5783
Joe Perchesb6b38f72010-04-21 03:50:45 +00005784 cFYI(1, "In SetAttrLegacy");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005785
5786SetAttrLgcyRetry:
5787 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5788 (void **) &pSMBr);
5789 if (rc)
5790 return rc;
5791
5792 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5793 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005794 ConvertToUTF16((__le16 *) pSMB->fileName, fileName,
5795 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005796 name_len++; /* trailing null */
5797 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005798 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005799 name_len = strnlen(fileName, PATH_MAX);
5800 name_len++; /* trailing null */
5801 strncpy(pSMB->fileName, fileName, name_len);
5802 }
5803 pSMB->attr = cpu_to_le16(dos_attrs);
5804 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005805 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005806 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5807 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5808 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005809 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005810 cFYI(1, "Error in LegacySetAttr = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005811
5812 cifs_buf_release(pSMB);
5813
5814 if (rc == -EAGAIN)
5815 goto SetAttrLgcyRetry;
5816
5817 return rc;
5818}
5819#endif /* temporarily unneeded SetAttr legacy function */
5820
Jeff Layton654cf142009-07-09 20:02:49 -04005821static void
5822cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5823 const struct cifs_unix_set_info_args *args)
5824{
5825 u64 mode = args->mode;
5826
5827 /*
5828 * Samba server ignores set of file size to zero due to bugs in some
5829 * older clients, but we should be precise - we use SetFileSize to
5830 * set file size and do not want to truncate file size to zero
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005831 * accidentally as happened on one Samba server beta by putting
Jeff Layton654cf142009-07-09 20:02:49 -04005832 * zero instead of -1 here
5833 */
5834 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5835 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5836 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5837 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5838 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5839 data_offset->Uid = cpu_to_le64(args->uid);
5840 data_offset->Gid = cpu_to_le64(args->gid);
5841 /* better to leave device as zero when it is */
5842 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5843 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5844 data_offset->Permissions = cpu_to_le64(mode);
5845
5846 if (S_ISREG(mode))
5847 data_offset->Type = cpu_to_le32(UNIX_FILE);
5848 else if (S_ISDIR(mode))
5849 data_offset->Type = cpu_to_le32(UNIX_DIR);
5850 else if (S_ISLNK(mode))
5851 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5852 else if (S_ISCHR(mode))
5853 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5854 else if (S_ISBLK(mode))
5855 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5856 else if (S_ISFIFO(mode))
5857 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5858 else if (S_ISSOCK(mode))
5859 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5860}
5861
Linus Torvalds1da177e2005-04-16 15:20:36 -07005862int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005863CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005864 const struct cifs_unix_set_info_args *args,
5865 u16 fid, u32 pid_of_opener)
5866{
5867 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005868 char *data_offset;
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005869 int rc = 0;
5870 u16 params, param_offset, offset, byte_count, count;
5871
Joe Perchesb6b38f72010-04-21 03:50:45 +00005872 cFYI(1, "Set Unix Info (via SetFileInfo)");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005873 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5874
5875 if (rc)
5876 return rc;
5877
5878 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5879 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5880
5881 params = 6;
5882 pSMB->MaxSetupCount = 0;
5883 pSMB->Reserved = 0;
5884 pSMB->Flags = 0;
5885 pSMB->Timeout = 0;
5886 pSMB->Reserved2 = 0;
5887 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5888 offset = param_offset + params;
5889
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005890 data_offset = (char *)pSMB +
5891 offsetof(struct smb_hdr, Protocol) + offset;
5892
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005893 count = sizeof(FILE_UNIX_BASIC_INFO);
5894
5895 pSMB->MaxParameterCount = cpu_to_le16(2);
5896 /* BB find max SMB PDU from sess */
5897 pSMB->MaxDataCount = cpu_to_le16(1000);
5898 pSMB->SetupCount = 1;
5899 pSMB->Reserved3 = 0;
5900 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5901 byte_count = 3 /* pad */ + params + count;
5902 pSMB->DataCount = cpu_to_le16(count);
5903 pSMB->ParameterCount = cpu_to_le16(params);
5904 pSMB->TotalDataCount = pSMB->DataCount;
5905 pSMB->TotalParameterCount = pSMB->ParameterCount;
5906 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5907 pSMB->DataOffset = cpu_to_le16(offset);
5908 pSMB->Fid = fid;
5909 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5910 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005911 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005912 pSMB->ByteCount = cpu_to_le16(byte_count);
5913
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005914 cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005915
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005916 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005917 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005918 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005919
5920 /* Note: On -EAGAIN error only caller can retry on handle based calls
5921 since file handle passed in no longer valid */
5922
5923 return rc;
5924}
5925
5926int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005927CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005928 const char *file_name,
Jeff Layton01ea95e2009-07-09 20:02:49 -04005929 const struct cifs_unix_set_info_args *args,
5930 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005931{
5932 TRANSACTION2_SPI_REQ *pSMB = NULL;
5933 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5934 int name_len;
5935 int rc = 0;
5936 int bytes_returned = 0;
5937 FILE_UNIX_BASIC_INFO *data_offset;
5938 __u16 params, param_offset, offset, count, byte_count;
5939
Joe Perchesb6b38f72010-04-21 03:50:45 +00005940 cFYI(1, "In SetUID/GID/Mode");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005941setPermsRetry:
5942 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5943 (void **) &pSMBr);
5944 if (rc)
5945 return rc;
5946
5947 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5948 name_len =
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005949 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06005950 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005951 name_len++; /* trailing null */
5952 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005953 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005954 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005955 name_len++; /* trailing null */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005956 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005957 }
5958
5959 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005960 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005961 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005962 /* BB find max SMB PDU from sess structure BB */
5963 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005964 pSMB->MaxSetupCount = 0;
5965 pSMB->Reserved = 0;
5966 pSMB->Flags = 0;
5967 pSMB->Timeout = 0;
5968 pSMB->Reserved2 = 0;
5969 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005970 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005971 offset = param_offset + params;
5972 data_offset =
5973 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5974 offset);
5975 memset(data_offset, 0, count);
5976 pSMB->DataOffset = cpu_to_le16(offset);
5977 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5978 pSMB->SetupCount = 1;
5979 pSMB->Reserved3 = 0;
5980 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5981 byte_count = 3 /* pad */ + params + count;
5982 pSMB->ParameterCount = cpu_to_le16(params);
5983 pSMB->DataCount = cpu_to_le16(count);
5984 pSMB->TotalParameterCount = pSMB->ParameterCount;
5985 pSMB->TotalDataCount = pSMB->DataCount;
5986 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5987 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005988 inc_rfc1001_len(pSMB, byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005989
Jeff Layton654cf142009-07-09 20:02:49 -04005990 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005991
5992 pSMB->ByteCount = cpu_to_le16(byte_count);
5993 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5994 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005995 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005996 cFYI(1, "SetPathInfo (perms) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005997
Steve French0d817bc2008-05-22 02:02:03 +00005998 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005999 if (rc == -EAGAIN)
6000 goto setPermsRetry;
6001 return rc;
6002}
6003
Linus Torvalds1da177e2005-04-16 15:20:36 -07006004#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05006005/*
6006 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
6007 * function used by listxattr and getxattr type calls. When ea_name is set,
6008 * it looks for that attribute name and stuffs that value into the EAData
6009 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
6010 * buffer. In both cases, the return value is either the length of the
6011 * resulting data or a negative error code. If EAData is a NULL pointer then
6012 * the data isn't copied to it, but the length is returned.
6013 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006014ssize_t
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006015CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05006016 const unsigned char *searchName, const unsigned char *ea_name,
6017 char *EAData, size_t buf_size,
6018 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006019{
6020 /* BB assumes one setup word */
6021 TRANSACTION2_QPI_REQ *pSMB = NULL;
6022 TRANSACTION2_QPI_RSP *pSMBr = NULL;
6023 int rc = 0;
6024 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05006025 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006026 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00006027 struct fea *temp_fea;
6028 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006029 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006030 __u16 params, byte_count, data_offset;
Jeff Layton5980fc92011-07-28 12:48:26 -04006031 unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006032
Joe Perchesb6b38f72010-04-21 03:50:45 +00006033 cFYI(1, "In Query All EAs path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006034QAllEAsRetry:
6035 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6036 (void **) &pSMBr);
6037 if (rc)
6038 return rc;
6039
6040 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05006041 list_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006042 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
6043 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05006044 list_len++; /* trailing null */
6045 list_len *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006046 } else { /* BB improve the check for buffer overruns BB */
Jeff Layton6e462b92010-02-10 16:18:26 -05006047 list_len = strnlen(searchName, PATH_MAX);
6048 list_len++; /* trailing null */
6049 strncpy(pSMB->FileName, searchName, list_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006050 }
6051
Jeff Layton6e462b92010-02-10 16:18:26 -05006052 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006053 pSMB->TotalDataCount = 0;
6054 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006055 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05006056 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006057 pSMB->MaxSetupCount = 0;
6058 pSMB->Reserved = 0;
6059 pSMB->Flags = 0;
6060 pSMB->Timeout = 0;
6061 pSMB->Reserved2 = 0;
6062 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00006063 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006064 pSMB->DataCount = 0;
6065 pSMB->DataOffset = 0;
6066 pSMB->SetupCount = 1;
6067 pSMB->Reserved3 = 0;
6068 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
6069 byte_count = params + 1 /* pad */ ;
6070 pSMB->TotalParameterCount = cpu_to_le16(params);
6071 pSMB->ParameterCount = pSMB->TotalParameterCount;
6072 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
6073 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006074 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006075 pSMB->ByteCount = cpu_to_le16(byte_count);
6076
6077 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6078 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6079 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006080 cFYI(1, "Send error in QueryAllEAs = %d", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05006081 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006082 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006083
6084
6085 /* BB also check enough total bytes returned */
6086 /* BB we need to improve the validity checking
6087 of these trans2 responses */
6088
6089 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Jeff Layton820a8032011-05-04 08:05:26 -04006090 if (rc || get_bcc(&pSMBr->hdr) < 4) {
Jeff Laytonf0d38682010-02-10 16:18:26 -05006091 rc = -EIO; /* bad smb */
6092 goto QAllEAsOut;
6093 }
6094
6095 /* check that length of list is not more than bcc */
6096 /* check that each entry does not go beyond length
6097 of list */
6098 /* check that each element of each entry does not
6099 go beyond end of list */
6100 /* validate_trans2_offsets() */
6101 /* BB check if start of smb + data_offset > &bcc+ bcc */
6102
6103 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
6104 ea_response_data = (struct fealist *)
6105 (((char *) &pSMBr->hdr.Protocol) + data_offset);
6106
Jeff Layton6e462b92010-02-10 16:18:26 -05006107 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesb6b38f72010-04-21 03:50:45 +00006108 cFYI(1, "ea length %d", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05006109 if (list_len <= 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006110 cFYI(1, "empty EA list returned from server");
Jeff Laytonf0d38682010-02-10 16:18:26 -05006111 goto QAllEAsOut;
6112 }
6113
Jeff Layton0cd126b2010-02-10 16:18:26 -05006114 /* make sure list_len doesn't go past end of SMB */
Jeff Layton690c5222011-01-20 13:36:51 -05006115 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
Jeff Layton0cd126b2010-02-10 16:18:26 -05006116 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006117 cFYI(1, "EA list appears to go beyond SMB");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006118 rc = -EIO;
6119 goto QAllEAsOut;
6120 }
6121
Jeff Laytonf0d38682010-02-10 16:18:26 -05006122 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05006123 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006124 temp_fea = ea_response_data->list;
6125 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05006126 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00006127 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006128 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006129
Jeff Layton6e462b92010-02-10 16:18:26 -05006130 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006131 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006132 /* make sure we can read name_len and value_len */
6133 if (list_len < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006134 cFYI(1, "EA entry goes beyond length of list");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006135 rc = -EIO;
6136 goto QAllEAsOut;
6137 }
6138
6139 name_len = temp_fea->name_len;
6140 value_len = le16_to_cpu(temp_fea->value_len);
6141 list_len -= name_len + 1 + value_len;
6142 if (list_len < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006143 cFYI(1, "EA entry goes beyond length of list");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006144 rc = -EIO;
6145 goto QAllEAsOut;
6146 }
6147
Jeff Layton31c05192010-02-10 16:18:26 -05006148 if (ea_name) {
Jeff Layton91d065c2011-07-26 18:23:47 -04006149 if (ea_name_len == name_len &&
Jeff Laytonac423442011-10-11 06:41:32 -04006150 memcmp(ea_name, temp_ptr, name_len) == 0) {
Jeff Layton31c05192010-02-10 16:18:26 -05006151 temp_ptr += name_len + 1;
6152 rc = value_len;
6153 if (buf_size == 0)
6154 goto QAllEAsOut;
6155 if ((size_t)value_len > buf_size) {
6156 rc = -ERANGE;
6157 goto QAllEAsOut;
6158 }
6159 memcpy(EAData, temp_ptr, value_len);
6160 goto QAllEAsOut;
6161 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006162 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05006163 /* account for prefix user. and trailing null */
6164 rc += (5 + 1 + name_len);
6165 if (rc < (int) buf_size) {
6166 memcpy(EAData, "user.", 5);
6167 EAData += 5;
6168 memcpy(EAData, temp_ptr, name_len);
6169 EAData += name_len;
6170 /* null terminate name */
6171 *EAData = 0;
6172 ++EAData;
6173 } else if (buf_size == 0) {
6174 /* skip copy - calc size only */
6175 } else {
6176 /* stop before overrun buffer */
6177 rc = -ERANGE;
6178 break;
6179 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006180 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05006181 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006182 temp_fea = (struct fea *)temp_ptr;
6183 }
6184
Jeff Layton31c05192010-02-10 16:18:26 -05006185 /* didn't find the named attribute */
6186 if (ea_name)
6187 rc = -ENODATA;
6188
Jeff Laytonf0d38682010-02-10 16:18:26 -05006189QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00006190 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006191 if (rc == -EAGAIN)
6192 goto QAllEAsRetry;
6193
6194 return (ssize_t)rc;
6195}
6196
Linus Torvalds1da177e2005-04-16 15:20:36 -07006197int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006198CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
6199 const char *fileName, const char *ea_name, const void *ea_value,
Steve French50c2f752007-07-13 00:33:32 +00006200 const __u16 ea_value_len, const struct nls_table *nls_codepage,
6201 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006202{
6203 struct smb_com_transaction2_spi_req *pSMB = NULL;
6204 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
6205 struct fealist *parm_data;
6206 int name_len;
6207 int rc = 0;
6208 int bytes_returned = 0;
6209 __u16 params, param_offset, byte_count, offset, count;
6210
Joe Perchesb6b38f72010-04-21 03:50:45 +00006211 cFYI(1, "In SetEA");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006212SetEARetry:
6213 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6214 (void **) &pSMBr);
6215 if (rc)
6216 return rc;
6217
6218 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6219 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006220 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
6221 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006222 name_len++; /* trailing null */
6223 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00006224 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006225 name_len = strnlen(fileName, PATH_MAX);
6226 name_len++; /* trailing null */
6227 strncpy(pSMB->FileName, fileName, name_len);
6228 }
6229
6230 params = 6 + name_len;
6231
6232 /* done calculating parms using name_len of file name,
6233 now use name_len to calculate length of ea name
6234 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00006235 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006236 name_len = 0;
6237 else
Steve French50c2f752007-07-13 00:33:32 +00006238 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006239
Steve Frenchdae5dbd2007-12-30 23:49:57 +00006240 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006241 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006242 /* BB find max SMB PDU from sess */
6243 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006244 pSMB->MaxSetupCount = 0;
6245 pSMB->Reserved = 0;
6246 pSMB->Flags = 0;
6247 pSMB->Timeout = 0;
6248 pSMB->Reserved2 = 0;
6249 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006250 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006251 offset = param_offset + params;
6252 pSMB->InformationLevel =
6253 cpu_to_le16(SMB_SET_FILE_EA);
6254
6255 parm_data =
6256 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
6257 offset);
6258 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6259 pSMB->DataOffset = cpu_to_le16(offset);
6260 pSMB->SetupCount = 1;
6261 pSMB->Reserved3 = 0;
6262 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6263 byte_count = 3 /* pad */ + params + count;
6264 pSMB->DataCount = cpu_to_le16(count);
6265 parm_data->list_len = cpu_to_le32(count);
6266 parm_data->list[0].EA_flags = 0;
6267 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08006268 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006269 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00006270 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00006271 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006272 parm_data->list[0].name[name_len] = 0;
6273 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
6274 /* caller ensures that ea_value_len is less than 64K but
6275 we need to ensure that it fits within the smb */
6276
Steve French50c2f752007-07-13 00:33:32 +00006277 /*BB add length check to see if it would fit in
6278 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00006279 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
6280 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00006281 memcpy(parm_data->list[0].name+name_len+1,
6282 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006283
6284 pSMB->TotalDataCount = pSMB->DataCount;
6285 pSMB->ParameterCount = cpu_to_le16(params);
6286 pSMB->TotalParameterCount = pSMB->ParameterCount;
6287 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006288 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006289 pSMB->ByteCount = cpu_to_le16(byte_count);
6290 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6291 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006292 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00006293 cFYI(1, "SetPathInfo (EA) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006294
6295 cifs_buf_release(pSMB);
6296
6297 if (rc == -EAGAIN)
6298 goto SetEARetry;
6299
6300 return rc;
6301}
Linus Torvalds1da177e2005-04-16 15:20:36 -07006302#endif
Steve French0eff0e22011-02-24 05:39:23 +00006303
6304#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */
6305/*
6306 * Years ago the kernel added a "dnotify" function for Samba server,
6307 * to allow network clients (such as Windows) to display updated
6308 * lists of files in directory listings automatically when
6309 * files are added by one user when another user has the
6310 * same directory open on their desktop. The Linux cifs kernel
6311 * client hooked into the kernel side of this interface for
6312 * the same reason, but ironically when the VFS moved from
6313 * "dnotify" to "inotify" it became harder to plug in Linux
6314 * network file system clients (the most obvious use case
6315 * for notify interfaces is when multiple users can update
6316 * the contents of the same directory - exactly what network
6317 * file systems can do) although the server (Samba) could
6318 * still use it. For the short term we leave the worker
6319 * function ifdeffed out (below) until inotify is fixed
6320 * in the VFS to make it easier to plug in network file
6321 * system clients. If inotify turns out to be permanently
6322 * incompatible for network fs clients, we could instead simply
6323 * expose this config flag by adding a future cifs (and smb2) notify ioctl.
6324 */
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006325int CIFSSMBNotify(const unsigned int xid, struct cifs_tcon *tcon,
Steve French0eff0e22011-02-24 05:39:23 +00006326 const int notify_subdirs, const __u16 netfid,
6327 __u32 filter, struct file *pfile, int multishot,
6328 const struct nls_table *nls_codepage)
6329{
6330 int rc = 0;
6331 struct smb_com_transaction_change_notify_req *pSMB = NULL;
6332 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
6333 struct dir_notify_req *dnotify_req;
6334 int bytes_returned;
6335
6336 cFYI(1, "In CIFSSMBNotify for file handle %d", (int)netfid);
6337 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
6338 (void **) &pSMBr);
6339 if (rc)
6340 return rc;
6341
6342 pSMB->TotalParameterCount = 0 ;
6343 pSMB->TotalDataCount = 0;
6344 pSMB->MaxParameterCount = cpu_to_le32(2);
Jeff Laytonc974bef2011-10-11 06:41:32 -04006345 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Steve French0eff0e22011-02-24 05:39:23 +00006346 pSMB->MaxSetupCount = 4;
6347 pSMB->Reserved = 0;
6348 pSMB->ParameterOffset = 0;
6349 pSMB->DataCount = 0;
6350 pSMB->DataOffset = 0;
6351 pSMB->SetupCount = 4; /* single byte does not need le conversion */
6352 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
6353 pSMB->ParameterCount = pSMB->TotalParameterCount;
6354 if (notify_subdirs)
6355 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
6356 pSMB->Reserved2 = 0;
6357 pSMB->CompletionFilter = cpu_to_le32(filter);
6358 pSMB->Fid = netfid; /* file handle always le */
6359 pSMB->ByteCount = 0;
6360
6361 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6362 (struct smb_hdr *)pSMBr, &bytes_returned,
6363 CIFS_ASYNC_OP);
6364 if (rc) {
6365 cFYI(1, "Error in Notify = %d", rc);
6366 } else {
6367 /* Add file to outstanding requests */
6368 /* BB change to kmem cache alloc */
6369 dnotify_req = kmalloc(
6370 sizeof(struct dir_notify_req),
6371 GFP_KERNEL);
6372 if (dnotify_req) {
6373 dnotify_req->Pid = pSMB->hdr.Pid;
6374 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
6375 dnotify_req->Mid = pSMB->hdr.Mid;
6376 dnotify_req->Tid = pSMB->hdr.Tid;
6377 dnotify_req->Uid = pSMB->hdr.Uid;
6378 dnotify_req->netfid = netfid;
6379 dnotify_req->pfile = pfile;
6380 dnotify_req->filter = filter;
6381 dnotify_req->multishot = multishot;
6382 spin_lock(&GlobalMid_Lock);
6383 list_add_tail(&dnotify_req->lhead,
6384 &GlobalDnotifyReqList);
6385 spin_unlock(&GlobalMid_Lock);
6386 } else
6387 rc = -ENOMEM;
6388 }
6389 cifs_buf_release(pSMB);
6390 return rc;
6391}
6392#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */