blob: 5d7bd757dcf1f961e334e95aaee2ffca0bd1db4d [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 Laytonfec344e2012-09-18 16:20:35 -0700728 struct smb_rqst rqst = { .rq_iov = &iov,
729 .rq_nvec = 1 };
Jeff Layton766fdbb2011-01-11 07:24:21 -0500730
731 cFYI(1, "In echo request");
732
733 rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
734 if (rc)
735 return rc;
736
737 /* set up echo request */
Steve French5443d132011-03-13 05:08:25 +0000738 smb->hdr.Tid = 0xffff;
Jeff Layton99d86c8f2011-01-20 21:19:25 -0500739 smb->hdr.WordCount = 1;
740 put_unaligned_le16(1, &smb->EchoCount);
Jeff Layton820a8032011-05-04 08:05:26 -0400741 put_bcc(1, &smb->hdr);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500742 smb->Data[0] = 'a';
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000743 inc_rfc1001_len(smb, 3);
Jeff Laytonfcc31cb2011-05-19 16:22:53 -0400744 iov.iov_base = smb;
745 iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
Jeff Layton766fdbb2011-01-11 07:24:21 -0500746
Jeff Laytonfec344e2012-09-18 16:20:35 -0700747 rc = cifs_call_async(server, &rqst, NULL, cifs_echo_callback,
Pavel Shilovskya891f0f2012-05-23 16:14:34 +0400748 server, CIFS_ASYNC_OP | CIFS_ECHO_OP);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500749 if (rc)
750 cFYI(1, "Echo request failed: %d", rc);
751
752 cifs_small_buf_release(smb);
753
754 return rc;
755}
756
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757int
Pavel Shilovsky58c45c52012-05-25 10:54:49 +0400758CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 LOGOFF_ANDX_REQ *pSMB;
761 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762
Joe Perchesb6b38f72010-04-21 03:50:45 +0000763 cFYI(1, "In SMBLogoff for session disconnect");
Jeff Layton14fbf502008-11-14 13:53:46 -0500764
765 /*
766 * BB: do we need to check validity of ses and server? They should
767 * always be valid since we have an active reference. If not, that
768 * should probably be a BUG()
769 */
770 if (!ses || !ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 return -EIO;
772
Steve Frenchd7b619c2010-02-25 05:36:46 +0000773 mutex_lock(&ses->session_mutex);
Steve French3b795212008-11-13 19:45:32 +0000774 if (ses->need_reconnect)
775 goto session_already_dead; /* no need to send SMBlogoff if uid
776 already closed due to reconnect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
778 if (rc) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000779 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 return rc;
781 }
782
Pavel Shilovsky88257362012-05-23 14:01:59 +0400783 pSMB->hdr.Mid = get_next_mid(ses->server);
Steve French1982c342005-08-17 12:38:22 -0700784
Steve French96daf2b2011-05-27 04:34:02 +0000785 if (ses->server->sec_mode &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
787 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788
789 pSMB->hdr.Uid = ses->Suid;
790
791 pSMB->AndXCommand = 0xFF;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400792 rc = SendReceiveNoRsp(xid, ses, (char *) pSMB, 0);
Steve French3b795212008-11-13 19:45:32 +0000793session_already_dead:
Steve Frenchd7b619c2010-02-25 05:36:46 +0000794 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795
796 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000797 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 error */
799 if (rc == -EAGAIN)
800 rc = 0;
801 return rc;
802}
803
804int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400805CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
806 const char *fileName, __u16 type,
807 const struct nls_table *nls_codepage, int remap)
Steve French2d785a52007-07-15 01:48:57 +0000808{
809 TRANSACTION2_SPI_REQ *pSMB = NULL;
810 TRANSACTION2_SPI_RSP *pSMBr = NULL;
811 struct unlink_psx_rq *pRqD;
812 int name_len;
813 int rc = 0;
814 int bytes_returned = 0;
815 __u16 params, param_offset, offset, byte_count;
816
Joe Perchesb6b38f72010-04-21 03:50:45 +0000817 cFYI(1, "In POSIX delete");
Steve French2d785a52007-07-15 01:48:57 +0000818PsxDelete:
819 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
820 (void **) &pSMBr);
821 if (rc)
822 return rc;
823
824 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
825 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -0600826 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
827 PATH_MAX, nls_codepage, remap);
Steve French2d785a52007-07-15 01:48:57 +0000828 name_len++; /* trailing null */
829 name_len *= 2;
830 } else { /* BB add path length overrun check */
831 name_len = strnlen(fileName, PATH_MAX);
832 name_len++; /* trailing null */
833 strncpy(pSMB->FileName, fileName, name_len);
834 }
835
836 params = 6 + name_len;
837 pSMB->MaxParameterCount = cpu_to_le16(2);
838 pSMB->MaxDataCount = 0; /* BB double check this with jra */
839 pSMB->MaxSetupCount = 0;
840 pSMB->Reserved = 0;
841 pSMB->Flags = 0;
842 pSMB->Timeout = 0;
843 pSMB->Reserved2 = 0;
844 param_offset = offsetof(struct smb_com_transaction2_spi_req,
845 InformationLevel) - 4;
846 offset = param_offset + params;
847
848 /* Setup pointer to Request Data (inode type) */
849 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
850 pRqD->type = cpu_to_le16(type);
851 pSMB->ParameterOffset = cpu_to_le16(param_offset);
852 pSMB->DataOffset = cpu_to_le16(offset);
853 pSMB->SetupCount = 1;
854 pSMB->Reserved3 = 0;
855 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
856 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
857
858 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
859 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
860 pSMB->ParameterCount = cpu_to_le16(params);
861 pSMB->TotalParameterCount = pSMB->ParameterCount;
862 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
863 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000864 inc_rfc1001_len(pSMB, byte_count);
Steve French2d785a52007-07-15 01:48:57 +0000865 pSMB->ByteCount = cpu_to_le16(byte_count);
866 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
867 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000868 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000869 cFYI(1, "Posix delete returned %d", rc);
Steve French2d785a52007-07-15 01:48:57 +0000870 cifs_buf_release(pSMB);
871
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400872 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve French2d785a52007-07-15 01:48:57 +0000873
874 if (rc == -EAGAIN)
875 goto PsxDelete;
876
877 return rc;
878}
879
880int
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700881CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
882 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883{
884 DELETE_FILE_REQ *pSMB = NULL;
885 DELETE_FILE_RSP *pSMBr = NULL;
886 int rc = 0;
887 int bytes_returned;
888 int name_len;
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700889 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890
891DelFileRetry:
892 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
893 (void **) &pSMBr);
894 if (rc)
895 return rc;
896
897 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700898 name_len = cifsConvertToUTF16((__le16 *) pSMB->fileName, name,
899 PATH_MAX, cifs_sb->local_nls,
900 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 name_len++; /* trailing null */
902 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700903 } else { /* BB improve check for buffer overruns BB */
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700904 name_len = strnlen(name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 name_len++; /* trailing null */
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700906 strncpy(pSMB->fileName, name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907 }
908 pSMB->SearchAttributes =
909 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
910 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000911 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 pSMB->ByteCount = cpu_to_le16(name_len + 1);
913 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
914 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400915 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000916 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000917 cFYI(1, "Error in RMFile = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918
919 cifs_buf_release(pSMB);
920 if (rc == -EAGAIN)
921 goto DelFileRetry;
922
923 return rc;
924}
925
926int
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400927CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
928 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929{
930 DELETE_DIRECTORY_REQ *pSMB = NULL;
931 DELETE_DIRECTORY_RSP *pSMBr = NULL;
932 int rc = 0;
933 int bytes_returned;
934 int name_len;
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400935 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936
Joe Perchesb6b38f72010-04-21 03:50:45 +0000937 cFYI(1, "In CIFSSMBRmDir");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938RmDirRetry:
939 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
940 (void **) &pSMBr);
941 if (rc)
942 return rc;
943
944 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400945 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
946 PATH_MAX, cifs_sb->local_nls,
947 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948 name_len++; /* trailing null */
949 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700950 } else { /* BB improve check for buffer overruns BB */
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400951 name_len = strnlen(name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952 name_len++; /* trailing null */
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400953 strncpy(pSMB->DirName, name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954 }
955
956 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000957 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958 pSMB->ByteCount = cpu_to_le16(name_len + 1);
959 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
960 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400961 cifs_stats_inc(&tcon->stats.cifs_stats.num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000962 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000963 cFYI(1, "Error in RMDir = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964
965 cifs_buf_release(pSMB);
966 if (rc == -EAGAIN)
967 goto RmDirRetry;
968 return rc;
969}
970
971int
Pavel Shilovskyf4367202012-03-17 11:41:12 +0300972CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
973 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974{
975 int rc = 0;
976 CREATE_DIRECTORY_REQ *pSMB = NULL;
977 CREATE_DIRECTORY_RSP *pSMBr = NULL;
978 int bytes_returned;
979 int name_len;
Pavel Shilovskyf4367202012-03-17 11:41:12 +0300980 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981
Joe Perchesb6b38f72010-04-21 03:50:45 +0000982 cFYI(1, "In CIFSSMBMkDir");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983MkDirRetry:
984 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
985 (void **) &pSMBr);
986 if (rc)
987 return rc;
988
989 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -0600990 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
Pavel Shilovskyf4367202012-03-17 11:41:12 +0300991 PATH_MAX, cifs_sb->local_nls,
992 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993 name_len++; /* trailing null */
994 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700995 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 name_len = strnlen(name, PATH_MAX);
997 name_len++; /* trailing null */
998 strncpy(pSMB->DirName, name, name_len);
999 }
1000
1001 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001002 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 pSMB->ByteCount = cpu_to_le16(name_len + 1);
1004 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1005 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001006 cifs_stats_inc(&tcon->stats.cifs_stats.num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +00001007 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001008 cFYI(1, "Error in Mkdir = %d", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07001009
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 cifs_buf_release(pSMB);
1011 if (rc == -EAGAIN)
1012 goto MkDirRetry;
1013 return rc;
1014}
1015
Steve French2dd29d32007-04-23 22:07:35 +00001016int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001017CIFSPOSIXCreate(const unsigned int xid, struct cifs_tcon *tcon,
1018 __u32 posix_flags, __u64 mode, __u16 *netfid,
1019 FILE_UNIX_BASIC_INFO *pRetData, __u32 *pOplock,
1020 const char *name, const struct nls_table *nls_codepage,
1021 int remap)
Steve French2dd29d32007-04-23 22:07:35 +00001022{
1023 TRANSACTION2_SPI_REQ *pSMB = NULL;
1024 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1025 int name_len;
1026 int rc = 0;
1027 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001028 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +00001029 OPEN_PSX_REQ *pdata;
1030 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +00001031
Joe Perchesb6b38f72010-04-21 03:50:45 +00001032 cFYI(1, "In POSIX Create");
Steve French2dd29d32007-04-23 22:07:35 +00001033PsxCreat:
1034 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1035 (void **) &pSMBr);
1036 if (rc)
1037 return rc;
1038
1039 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1040 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001041 cifsConvertToUTF16((__le16 *) pSMB->FileName, name,
1042 PATH_MAX, nls_codepage, remap);
Steve French2dd29d32007-04-23 22:07:35 +00001043 name_len++; /* trailing null */
1044 name_len *= 2;
1045 } else { /* BB improve the check for buffer overruns BB */
1046 name_len = strnlen(name, PATH_MAX);
1047 name_len++; /* trailing null */
1048 strncpy(pSMB->FileName, name, name_len);
1049 }
1050
1051 params = 6 + name_len;
1052 count = sizeof(OPEN_PSX_REQ);
1053 pSMB->MaxParameterCount = cpu_to_le16(2);
1054 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1055 pSMB->MaxSetupCount = 0;
1056 pSMB->Reserved = 0;
1057 pSMB->Flags = 0;
1058 pSMB->Timeout = 0;
1059 pSMB->Reserved2 = 0;
1060 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001061 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001062 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001063 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001064 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001065 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001066 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001067 pdata->OpenFlags = cpu_to_le32(*pOplock);
1068 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1069 pSMB->DataOffset = cpu_to_le16(offset);
1070 pSMB->SetupCount = 1;
1071 pSMB->Reserved3 = 0;
1072 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1073 byte_count = 3 /* pad */ + params + count;
1074
1075 pSMB->DataCount = cpu_to_le16(count);
1076 pSMB->ParameterCount = cpu_to_le16(params);
1077 pSMB->TotalDataCount = pSMB->DataCount;
1078 pSMB->TotalParameterCount = pSMB->ParameterCount;
1079 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1080 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001081 inc_rfc1001_len(pSMB, byte_count);
Steve French2dd29d32007-04-23 22:07:35 +00001082 pSMB->ByteCount = cpu_to_le16(byte_count);
1083 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1084 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1085 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001086 cFYI(1, "Posix create returned %d", rc);
Steve French2dd29d32007-04-23 22:07:35 +00001087 goto psx_create_err;
1088 }
1089
Joe Perchesb6b38f72010-04-21 03:50:45 +00001090 cFYI(1, "copying inode info");
Steve French2dd29d32007-04-23 22:07:35 +00001091 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1092
Jeff Layton820a8032011-05-04 08:05:26 -04001093 if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) {
Steve French2dd29d32007-04-23 22:07:35 +00001094 rc = -EIO; /* bad smb */
1095 goto psx_create_err;
1096 }
1097
1098 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001099 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001100 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001101
Steve French2dd29d32007-04-23 22:07:35 +00001102 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001103 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001104 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1105 /* Let caller know file was created so we can set the mode. */
1106 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001107 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001108 *pOplock |= CIFS_CREATE_ACTION;
1109 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001110 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1111 pRetData->Type = cpu_to_le32(-1); /* unknown */
Joe Perchesb6b38f72010-04-21 03:50:45 +00001112 cFYI(DBG2, "unknown type");
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001113 } else {
Jeff Layton820a8032011-05-04 08:05:26 -04001114 if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001115 + sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001116 cERROR(1, "Open response data too small");
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001117 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001118 goto psx_create_err;
1119 }
Steve French50c2f752007-07-13 00:33:32 +00001120 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001121 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001122 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001123 }
Steve French2dd29d32007-04-23 22:07:35 +00001124
1125psx_create_err:
1126 cifs_buf_release(pSMB);
1127
Steve French65bc98b2009-07-10 15:27:25 +00001128 if (posix_flags & SMB_O_DIRECTORY)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001129 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixmkdirs);
Steve French65bc98b2009-07-10 15:27:25 +00001130 else
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001131 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixopens);
Steve French2dd29d32007-04-23 22:07:35 +00001132
1133 if (rc == -EAGAIN)
1134 goto PsxCreat;
1135
Steve French50c2f752007-07-13 00:33:32 +00001136 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001137}
1138
Steve Frencha9d02ad2005-08-24 23:06:05 -07001139static __u16 convert_disposition(int disposition)
1140{
1141 __u16 ofun = 0;
1142
1143 switch (disposition) {
1144 case FILE_SUPERSEDE:
1145 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1146 break;
1147 case FILE_OPEN:
1148 ofun = SMBOPEN_OAPPEND;
1149 break;
1150 case FILE_CREATE:
1151 ofun = SMBOPEN_OCREATE;
1152 break;
1153 case FILE_OPEN_IF:
1154 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1155 break;
1156 case FILE_OVERWRITE:
1157 ofun = SMBOPEN_OTRUNC;
1158 break;
1159 case FILE_OVERWRITE_IF:
1160 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1161 break;
1162 default:
Joe Perchesb6b38f72010-04-21 03:50:45 +00001163 cFYI(1, "unknown disposition %d", disposition);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001164 ofun = SMBOPEN_OAPPEND; /* regular open */
1165 }
1166 return ofun;
1167}
1168
Jeff Layton35fc37d2008-05-14 10:22:03 -07001169static int
1170access_flags_to_smbopen_mode(const int access_flags)
1171{
1172 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1173
1174 if (masked_flags == GENERIC_READ)
1175 return SMBOPEN_READ;
1176 else if (masked_flags == GENERIC_WRITE)
1177 return SMBOPEN_WRITE;
1178
1179 /* just go for read/write */
1180 return SMBOPEN_READWRITE;
1181}
1182
Steve Frencha9d02ad2005-08-24 23:06:05 -07001183int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001184SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001185 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001186 const int access_flags, const int create_options, __u16 *netfid,
1187 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001188 const struct nls_table *nls_codepage, int remap)
1189{
1190 int rc = -EACCES;
1191 OPENX_REQ *pSMB = NULL;
1192 OPENX_RSP *pSMBr = NULL;
1193 int bytes_returned;
1194 int name_len;
1195 __u16 count;
1196
1197OldOpenRetry:
1198 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1199 (void **) &pSMBr);
1200 if (rc)
1201 return rc;
1202
1203 pSMB->AndXCommand = 0xFF; /* none */
1204
1205 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1206 count = 1; /* account for one byte pad to word boundary */
1207 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001208 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1209 fileName, PATH_MAX, nls_codepage, remap);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001210 name_len++; /* trailing null */
1211 name_len *= 2;
1212 } else { /* BB improve check for buffer overruns BB */
1213 count = 0; /* no pad */
1214 name_len = strnlen(fileName, PATH_MAX);
1215 name_len++; /* trailing null */
1216 strncpy(pSMB->fileName, fileName, name_len);
1217 }
1218 if (*pOplock & REQ_OPLOCK)
1219 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001220 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001221 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001222
Steve Frencha9d02ad2005-08-24 23:06:05 -07001223 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001224 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001225 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1226 /* set file as system file if special file such
1227 as fifo and server expecting SFU style and
1228 no Unix extensions */
1229
Steve French790fe572007-07-07 19:25:05 +00001230 if (create_options & CREATE_OPTION_SPECIAL)
1231 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001232 else /* BB FIXME BB */
1233 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001234
Jeff Layton67750fb2008-05-09 22:28:02 +00001235 if (create_options & CREATE_OPTION_READONLY)
1236 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001237
1238 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001239/* pSMB->CreateOptions = cpu_to_le32(create_options &
1240 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001241 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001242
1243 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001244 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001245 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001246 inc_rfc1001_len(pSMB, count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001247
1248 pSMB->ByteCount = cpu_to_le16(count);
1249 /* long_op set to 1 to allow for oplock break timeouts */
1250 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001251 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001252 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001253 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001254 cFYI(1, "Error in Open = %d", rc);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001255 } else {
1256 /* BB verify if wct == 15 */
1257
Steve French582d21e2008-05-13 04:54:12 +00001258/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001259
1260 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1261 /* Let caller know file was created so we can set the mode. */
1262 /* Do we care about the CreateAction in any other cases? */
1263 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001264/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001265 *pOplock |= CIFS_CREATE_ACTION; */
1266 /* BB FIXME END */
1267
Steve French790fe572007-07-07 19:25:05 +00001268 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001269 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1270 pfile_info->LastAccessTime = 0; /* BB fixme */
1271 pfile_info->LastWriteTime = 0; /* BB fixme */
1272 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001273 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001274 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001275 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001276 pfile_info->AllocationSize =
1277 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1278 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001279 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001280 pfile_info->DeletePending = 0;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001281 }
1282 }
1283
1284 cifs_buf_release(pSMB);
1285 if (rc == -EAGAIN)
1286 goto OldOpenRetry;
1287 return rc;
1288}
1289
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001291CIFSSMBOpen(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001293 const int access_flags, const int create_options, __u16 *netfid,
1294 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001295 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296{
1297 int rc = -EACCES;
1298 OPEN_REQ *pSMB = NULL;
1299 OPEN_RSP *pSMBr = NULL;
1300 int bytes_returned;
1301 int name_len;
1302 __u16 count;
1303
1304openRetry:
1305 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1306 (void **) &pSMBr);
1307 if (rc)
1308 return rc;
1309
1310 pSMB->AndXCommand = 0xFF; /* none */
1311
1312 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1313 count = 1; /* account for one byte pad to word boundary */
1314 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001315 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1316 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317 name_len++; /* trailing null */
1318 name_len *= 2;
1319 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001320 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321 count = 0; /* no pad */
1322 name_len = strnlen(fileName, PATH_MAX);
1323 name_len++; /* trailing null */
1324 pSMB->NameLength = cpu_to_le16(name_len);
1325 strncpy(pSMB->fileName, fileName, name_len);
1326 }
1327 if (*pOplock & REQ_OPLOCK)
1328 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001329 else if (*pOplock & REQ_BATCHOPLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1332 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -07001333 /* set file as system file if special file such
1334 as fifo and server expecting SFU style and
1335 no Unix extensions */
Steve French790fe572007-07-07 19:25:05 +00001336 if (create_options & CREATE_OPTION_SPECIAL)
Steve Frencheda3c0292005-07-21 15:20:28 -07001337 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1338 else
1339 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Jeff Layton67750fb2008-05-09 22:28:02 +00001340
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341 /* XP does not handle ATTR_POSIX_SEMANTICS */
1342 /* but it helps speed up case sensitive checks for other
1343 servers such as Samba */
1344 if (tcon->ses->capabilities & CAP_UNIX)
1345 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1346
Jeff Layton67750fb2008-05-09 22:28:02 +00001347 if (create_options & CREATE_OPTION_READONLY)
1348 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1349
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1351 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -07001352 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001353 /* BB Expirement with various impersonation levels and verify */
1354 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355 pSMB->SecurityFlags =
1356 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1357
1358 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001359 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360
1361 pSMB->ByteCount = cpu_to_le16(count);
1362 /* long_op set to 1 to allow for oplock break timeouts */
1363 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001364 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001365 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001367 cFYI(1, "Error in Open = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368 } else {
Steve French09d1db52005-04-28 22:41:08 -07001369 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1371 /* Let caller know file was created so we can set the mode. */
1372 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001373 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve French50c2f752007-07-13 00:33:32 +00001374 *pOplock |= CIFS_CREATE_ACTION;
Steve French790fe572007-07-07 19:25:05 +00001375 if (pfile_info) {
Steve French61e74802008-12-03 00:57:54 +00001376 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1377 36 /* CreationTime to Attributes */);
1378 /* the file_info buf is endian converted by caller */
1379 pfile_info->AllocationSize = pSMBr->AllocationSize;
1380 pfile_info->EndOfFile = pSMBr->EndOfFile;
1381 pfile_info->NumberOfLinks = cpu_to_le32(1);
1382 pfile_info->DeletePending = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001385
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386 cifs_buf_release(pSMB);
1387 if (rc == -EAGAIN)
1388 goto openRetry;
1389 return rc;
1390}
1391
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001392/*
1393 * Discard any remaining data in the current SMB. To do this, we borrow the
1394 * current bigbuf.
1395 */
1396static int
1397cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1398{
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001399 unsigned int rfclen = get_rfc1002_length(server->smallbuf);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001400 int remaining = rfclen + 4 - server->total_read;
1401 struct cifs_readdata *rdata = mid->callback_data;
1402
1403 while (remaining > 0) {
1404 int length;
1405
1406 length = cifs_read_from_socket(server, server->bigbuf,
1407 min_t(unsigned int, remaining,
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001408 CIFSMaxBufSize + MAX_HEADER_SIZE(server)));
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001409 if (length < 0)
1410 return length;
1411 server->total_read += length;
1412 remaining -= length;
1413 }
1414
1415 dequeue_mid(mid, rdata->result);
1416 return 0;
1417}
1418
Pavel Shilovsky09a47072012-09-18 16:20:29 -07001419int
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001420cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1421{
1422 int length, len;
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001423 unsigned int data_offset, data_len;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001424 struct cifs_readdata *rdata = mid->callback_data;
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001425 char *buf = server->smallbuf;
1426 unsigned int buflen = get_rfc1002_length(buf) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001427
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001428 cFYI(1, "%s: mid=%llu offset=%llu bytes=%u", __func__,
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001429 mid->mid, rdata->offset, rdata->bytes);
1430
1431 /*
1432 * read the rest of READ_RSP header (sans Data array), or whatever we
1433 * can if there's not enough data. At this point, we've read down to
1434 * the Mid.
1435 */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001436 len = min_t(unsigned int, buflen, server->vals->read_rsp_size) -
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001437 HEADER_SIZE(server) + 1;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001438
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001439 rdata->iov[0].iov_base = buf + HEADER_SIZE(server) - 1;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001440 rdata->iov[0].iov_len = len;
1441
1442 length = cifs_readv_from_socket(server, rdata->iov, 1, len);
1443 if (length < 0)
1444 return length;
1445 server->total_read += length;
1446
1447 /* Was the SMB read successful? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001448 rdata->result = server->ops->map_error(buf, false);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001449 if (rdata->result != 0) {
1450 cFYI(1, "%s: server returned error %d", __func__,
1451 rdata->result);
1452 return cifs_readv_discard(server, mid);
1453 }
1454
1455 /* Is there enough to get to the rest of the READ_RSP header? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001456 if (server->total_read < server->vals->read_rsp_size) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001457 cFYI(1, "%s: server returned short header. got=%u expected=%zu",
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001458 __func__, server->total_read,
1459 server->vals->read_rsp_size);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001460 rdata->result = -EIO;
1461 return cifs_readv_discard(server, mid);
1462 }
1463
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001464 data_offset = server->ops->read_data_offset(buf) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001465 if (data_offset < server->total_read) {
1466 /*
1467 * win2k8 sometimes sends an offset of 0 when the read
1468 * is beyond the EOF. Treat it as if the data starts just after
1469 * the header.
1470 */
1471 cFYI(1, "%s: data offset (%u) inside read response header",
1472 __func__, data_offset);
1473 data_offset = server->total_read;
1474 } else if (data_offset > MAX_CIFS_SMALL_BUFFER_SIZE) {
1475 /* data_offset is beyond the end of smallbuf */
1476 cFYI(1, "%s: data offset (%u) beyond end of smallbuf",
1477 __func__, data_offset);
1478 rdata->result = -EIO;
1479 return cifs_readv_discard(server, mid);
1480 }
1481
1482 cFYI(1, "%s: total_read=%u data_offset=%u", __func__,
1483 server->total_read, data_offset);
1484
1485 len = data_offset - server->total_read;
1486 if (len > 0) {
1487 /* read any junk before data into the rest of smallbuf */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001488 rdata->iov[0].iov_base = buf + server->total_read;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001489 rdata->iov[0].iov_len = len;
1490 length = cifs_readv_from_socket(server, rdata->iov, 1, len);
1491 if (length < 0)
1492 return length;
1493 server->total_read += length;
1494 }
1495
1496 /* set up first iov for signature check */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001497 rdata->iov[0].iov_base = buf;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001498 rdata->iov[0].iov_len = server->total_read;
Jeff Layton8321fec2012-09-19 06:22:32 -07001499 rdata->nr_iov = 1;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001500 cFYI(1, "0: iov_base=%p iov_len=%zu",
1501 rdata->iov[0].iov_base, rdata->iov[0].iov_len);
1502
1503 /* how much data is in the response? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001504 data_len = server->ops->read_data_length(buf);
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001505 if (data_offset + data_len > buflen) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001506 /* data_len is corrupt -- discard frame */
1507 rdata->result = -EIO;
1508 return cifs_readv_discard(server, mid);
1509 }
1510
Jeff Layton8321fec2012-09-19 06:22:32 -07001511 length = rdata->read_into_pages(server, rdata, data_len);
1512 if (length < 0)
1513 return length;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001514
Jeff Layton8321fec2012-09-19 06:22:32 -07001515 server->total_read += length;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001516 rdata->bytes = length;
1517
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001518 cFYI(1, "total_read=%u buflen=%u remaining=%u", server->total_read,
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001519 buflen, data_len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001520
1521 /* discard anything left over */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001522 if (server->total_read < buflen)
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001523 return cifs_readv_discard(server, mid);
1524
1525 dequeue_mid(mid, false);
1526 return length;
1527}
1528
1529static void
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001530cifs_readv_callback(struct mid_q_entry *mid)
1531{
1532 struct cifs_readdata *rdata = mid->callback_data;
1533 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1534 struct TCP_Server_Info *server = tcon->ses->server;
Jeff Laytonbf5ea0e2012-09-18 16:20:34 -07001535 struct smb_rqst rqst = { .rq_iov = rdata->iov,
Jeff Layton8321fec2012-09-19 06:22:32 -07001536 .rq_nvec = rdata->nr_iov,
1537 .rq_pages = rdata->pages,
1538 .rq_npages = rdata->nr_pages,
1539 .rq_pagesz = rdata->pagesz,
1540 .rq_tailsz = rdata->tailsz };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001541
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001542 cFYI(1, "%s: mid=%llu state=%d result=%d bytes=%u", __func__,
1543 mid->mid, mid->mid_state, rdata->result, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001544
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001545 switch (mid->mid_state) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001546 case MID_RESPONSE_RECEIVED:
1547 /* result already set, check signature */
1548 if (server->sec_mode &
1549 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
Steve French985e4ff02012-08-03 09:42:45 -05001550 int rc = 0;
1551
Jeff Laytonbf5ea0e2012-09-18 16:20:34 -07001552 rc = cifs_verify_signature(&rqst, server,
1553 mid->sequence_number + 1);
Steve French985e4ff02012-08-03 09:42:45 -05001554 if (rc)
1555 cERROR(1, "SMB signature verification returned "
1556 "error = %d", rc);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001557 }
1558 /* FIXME: should this be counted toward the initiating task? */
1559 task_io_account_read(rdata->bytes);
1560 cifs_stats_bytes_read(tcon, rdata->bytes);
1561 break;
1562 case MID_REQUEST_SUBMITTED:
1563 case MID_RETRY_NEEDED:
1564 rdata->result = -EAGAIN;
1565 break;
1566 default:
1567 rdata->result = -EIO;
1568 }
1569
Jeff Laytonda472fc2012-03-23 14:40:53 -04001570 queue_work(cifsiod_wq, &rdata->work);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001571 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04001572 add_credits(server, 1, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001573}
1574
1575/* cifs_async_readv - send an async write, and set up mid to handle result */
1576int
1577cifs_async_readv(struct cifs_readdata *rdata)
1578{
1579 int rc;
1580 READ_REQ *smb = NULL;
1581 int wct;
1582 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
Jeff Laytonfec344e2012-09-18 16:20:35 -07001583 struct smb_rqst rqst = { .rq_iov = rdata->iov,
1584 .rq_nvec = 1 };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001585
1586 cFYI(1, "%s: offset=%llu bytes=%u", __func__,
1587 rdata->offset, rdata->bytes);
1588
1589 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1590 wct = 12;
1591 else {
1592 wct = 10; /* old style read */
1593 if ((rdata->offset >> 32) > 0) {
1594 /* can not handle this big offset for old */
1595 return -EIO;
1596 }
1597 }
1598
1599 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **)&smb);
1600 if (rc)
1601 return rc;
1602
1603 smb->hdr.Pid = cpu_to_le16((__u16)rdata->pid);
1604 smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16));
1605
1606 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07001607 smb->Fid = rdata->cfile->fid.netfid;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001608 smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF);
1609 if (wct == 12)
1610 smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32);
1611 smb->Remaining = 0;
1612 smb->MaxCount = cpu_to_le16(rdata->bytes & 0xFFFF);
1613 smb->MaxCountHigh = cpu_to_le32(rdata->bytes >> 16);
1614 if (wct == 12)
1615 smb->ByteCount = 0;
1616 else {
1617 /* old style read */
1618 struct smb_com_readx_req *smbr =
1619 (struct smb_com_readx_req *)smb;
1620 smbr->ByteCount = 0;
1621 }
1622
1623 /* 4 for RFC1001 length + 1 for BCC */
1624 rdata->iov[0].iov_base = smb;
1625 rdata->iov[0].iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
1626
Jeff Layton6993f742012-05-16 07:13:17 -04001627 kref_get(&rdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07001628 rc = cifs_call_async(tcon->ses->server, &rqst, cifs_readv_receive,
1629 cifs_readv_callback, rdata, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001630
1631 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001632 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Jeff Layton6993f742012-05-16 07:13:17 -04001633 else
1634 kref_put(&rdata->refcount, cifs_readdata_release);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001635
1636 cifs_small_buf_release(smb);
1637 return rc;
1638}
1639
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001641CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
1642 unsigned int *nbytes, char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643{
1644 int rc = -EACCES;
1645 READ_REQ *pSMB = NULL;
1646 READ_RSP *pSMBr = NULL;
1647 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001648 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001649 int resp_buf_type = 0;
1650 struct kvec iov[1];
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001651 __u32 pid = io_parms->pid;
1652 __u16 netfid = io_parms->netfid;
1653 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001654 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001655 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656
Joe Perchesb6b38f72010-04-21 03:50:45 +00001657 cFYI(1, "Reading %d bytes on fid %d", count, netfid);
Steve French790fe572007-07-07 19:25:05 +00001658 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001659 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001660 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001661 wct = 10; /* old style read */
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001662 if ((offset >> 32) > 0) {
Steve French4c3130e2008-12-09 00:28:16 +00001663 /* can not handle this big offset for old */
1664 return -EIO;
1665 }
1666 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001667
1668 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001669 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670 if (rc)
1671 return rc;
1672
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001673 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1674 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1675
Linus Torvalds1da177e2005-04-16 15:20:36 -07001676 /* tcon and ses pointer are checked in smb_init */
1677 if (tcon->ses->server == NULL)
1678 return -ECONNABORTED;
1679
Steve Frenchec637e32005-12-12 20:53:18 -08001680 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001681 pSMB->Fid = netfid;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001682 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001683 if (wct == 12)
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001684 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001685
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686 pSMB->Remaining = 0;
1687 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1688 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001689 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001690 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1691 else {
1692 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001693 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001694 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001695 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001696 }
Steve Frenchec637e32005-12-12 20:53:18 -08001697
1698 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001699 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve Frencha761ac52007-10-18 21:45:27 +00001700 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Jeff Layton77499812011-01-11 07:24:23 -05001701 &resp_buf_type, CIFS_LOG_ERROR);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001702 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001703 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001705 cERROR(1, "Send error in read = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001706 } else {
1707 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1708 data_length = data_length << 16;
1709 data_length += le16_to_cpu(pSMBr->DataLength);
1710 *nbytes = data_length;
1711
1712 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001713 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714 || (data_length > count)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001715 cFYI(1, "bad length %d for count %d",
1716 data_length, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717 rc = -EIO;
1718 *nbytes = 0;
1719 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001720 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001721 le16_to_cpu(pSMBr->DataOffset);
1722/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001723 cERROR(1, "Faulting on read rc = %d",rc);
Steve French50c2f752007-07-13 00:33:32 +00001724 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001725 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001726 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001727 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728 }
1729 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730
Steve French4b8f9302006-02-26 16:41:18 +00001731/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001732 if (*buf) {
1733 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001734 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001735 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001736 cifs_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001737 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001738 /* return buffer to caller to free */
1739 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001740 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001741 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001742 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001743 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001744 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001745
1746 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001747 since file handle passed in no longer valid */
1748 return rc;
1749}
1750
Steve Frenchec637e32005-12-12 20:53:18 -08001751
Linus Torvalds1da177e2005-04-16 15:20:36 -07001752int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001753CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001754 unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001755 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001756{
1757 int rc = -EACCES;
1758 WRITE_REQ *pSMB = NULL;
1759 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001760 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761 __u32 bytes_sent;
1762 __u16 byte_count;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001763 __u32 pid = io_parms->pid;
1764 __u16 netfid = io_parms->netfid;
1765 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001766 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001767 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001768
Steve Frencha24e2d72010-04-03 17:20:21 +00001769 *nbytes = 0;
1770
Joe Perchesb6b38f72010-04-21 03:50:45 +00001771 /* cFYI(1, "write at %lld %d bytes", offset, count);*/
Steve French790fe572007-07-07 19:25:05 +00001772 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001773 return -ECONNABORTED;
1774
Steve French790fe572007-07-07 19:25:05 +00001775 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001776 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001777 else {
Steve French1c955182005-08-30 20:58:07 -07001778 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001779 if ((offset >> 32) > 0) {
1780 /* can not handle big offset for old srv */
1781 return -EIO;
1782 }
1783 }
Steve French1c955182005-08-30 20:58:07 -07001784
1785 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001786 (void **) &pSMBr);
1787 if (rc)
1788 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001789
1790 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1791 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1792
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793 /* tcon and ses pointer are checked in smb_init */
1794 if (tcon->ses->server == NULL)
1795 return -ECONNABORTED;
1796
1797 pSMB->AndXCommand = 0xFF; /* none */
1798 pSMB->Fid = netfid;
1799 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001800 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001801 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001802
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803 pSMB->Reserved = 0xFFFFFFFF;
1804 pSMB->WriteMode = 0;
1805 pSMB->Remaining = 0;
1806
Steve French50c2f752007-07-13 00:33:32 +00001807 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808 can send more if LARGE_WRITE_X capability returned by the server and if
1809 our buffer is big enough or if we convert to iovecs on socket writes
1810 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001811 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1813 } else {
1814 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1815 & ~0xFF;
1816 }
1817
1818 if (bytes_sent > count)
1819 bytes_sent = count;
1820 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001821 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001822 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001823 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001824 else if (ubuf) {
1825 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826 cifs_buf_release(pSMB);
1827 return -EFAULT;
1828 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001829 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830 /* No buffer */
1831 cifs_buf_release(pSMB);
1832 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001833 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001834 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001835 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001836 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001837 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001838
Linus Torvalds1da177e2005-04-16 15:20:36 -07001839 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1840 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001841 inc_rfc1001_len(pSMB, byte_count);
Steve French1c955182005-08-30 20:58:07 -07001842
Steve French790fe572007-07-07 19:25:05 +00001843 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001844 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001845 else { /* old style write has byte count 4 bytes earlier
1846 so 4 bytes pad */
1847 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001848 (struct smb_com_writex_req *)pSMB;
1849 pSMBW->ByteCount = cpu_to_le16(byte_count);
1850 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001851
1852 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1853 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001854 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00001856 cFYI(1, "Send error in write = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857 } else {
1858 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1859 *nbytes = (*nbytes) << 16;
1860 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301861
1862 /*
1863 * Mask off high 16 bits when bytes written as returned by the
1864 * server is greater than bytes requested by the client. Some
1865 * OS/2 servers are known to set incorrect CountHigh values.
1866 */
1867 if (*nbytes > count)
1868 *nbytes &= 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869 }
1870
1871 cifs_buf_release(pSMB);
1872
Steve French50c2f752007-07-13 00:33:32 +00001873 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874 since file handle passed in no longer valid */
1875
1876 return rc;
1877}
1878
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001879void
1880cifs_writedata_release(struct kref *refcount)
1881{
1882 struct cifs_writedata *wdata = container_of(refcount,
1883 struct cifs_writedata, refcount);
1884
1885 if (wdata->cfile)
1886 cifsFileInfo_put(wdata->cfile);
1887
1888 kfree(wdata);
1889}
1890
1891/*
1892 * Write failed with a retryable error. Resend the write request. It's also
1893 * possible that the page was redirtied so re-clean the page.
1894 */
1895static void
1896cifs_writev_requeue(struct cifs_writedata *wdata)
1897{
1898 int i, rc;
1899 struct inode *inode = wdata->cfile->dentry->d_inode;
Pavel Shilovskyc9de5c82012-09-18 16:20:29 -07001900 struct TCP_Server_Info *server;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001901
1902 for (i = 0; i < wdata->nr_pages; i++) {
1903 lock_page(wdata->pages[i]);
1904 clear_page_dirty_for_io(wdata->pages[i]);
1905 }
1906
1907 do {
Pavel Shilovskyc9de5c82012-09-18 16:20:29 -07001908 server = tlink_tcon(wdata->cfile->tlink)->ses->server;
1909 rc = server->ops->async_writev(wdata);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001910 } while (rc == -EAGAIN);
1911
1912 for (i = 0; i < wdata->nr_pages; i++) {
1913 if (rc != 0)
1914 SetPageError(wdata->pages[i]);
1915 unlock_page(wdata->pages[i]);
1916 }
1917
1918 mapping_set_error(inode->i_mapping, rc);
1919 kref_put(&wdata->refcount, cifs_writedata_release);
1920}
1921
Jeff Laytonc2e87642012-03-23 14:40:55 -04001922void
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001923cifs_writev_complete(struct work_struct *work)
1924{
1925 struct cifs_writedata *wdata = container_of(work,
1926 struct cifs_writedata, work);
1927 struct inode *inode = wdata->cfile->dentry->d_inode;
1928 int i = 0;
1929
1930 if (wdata->result == 0) {
Jeff Layton597b0272012-03-23 14:40:56 -04001931 spin_lock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001932 cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
Jeff Layton597b0272012-03-23 14:40:56 -04001933 spin_unlock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001934 cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
1935 wdata->bytes);
1936 } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
1937 return cifs_writev_requeue(wdata);
1938
1939 for (i = 0; i < wdata->nr_pages; i++) {
1940 struct page *page = wdata->pages[i];
1941 if (wdata->result == -EAGAIN)
1942 __set_page_dirty_nobuffers(page);
1943 else if (wdata->result < 0)
1944 SetPageError(page);
1945 end_page_writeback(page);
1946 page_cache_release(page);
1947 }
1948 if (wdata->result != -EAGAIN)
1949 mapping_set_error(inode->i_mapping, wdata->result);
1950 kref_put(&wdata->refcount, cifs_writedata_release);
1951}
1952
1953struct cifs_writedata *
Jeff Laytonc2e87642012-03-23 14:40:55 -04001954cifs_writedata_alloc(unsigned int nr_pages, work_func_t complete)
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001955{
1956 struct cifs_writedata *wdata;
1957
1958 /* this would overflow */
1959 if (nr_pages == 0) {
1960 cERROR(1, "%s: called with nr_pages == 0!", __func__);
1961 return NULL;
1962 }
1963
1964 /* writedata + number of page pointers */
1965 wdata = kzalloc(sizeof(*wdata) +
1966 sizeof(struct page *) * (nr_pages - 1), GFP_NOFS);
1967 if (wdata != NULL) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001968 kref_init(&wdata->refcount);
Jeff Laytonda82f7e2012-03-23 14:40:56 -04001969 INIT_LIST_HEAD(&wdata->list);
1970 init_completion(&wdata->done);
1971 INIT_WORK(&wdata->work, complete);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001972 }
1973 return wdata;
1974}
1975
1976/*
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001977 * Check the mid_state and signature on received buffer (if any), and queue the
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001978 * workqueue completion task.
1979 */
1980static void
1981cifs_writev_callback(struct mid_q_entry *mid)
1982{
1983 struct cifs_writedata *wdata = mid->callback_data;
Steve French96daf2b2011-05-27 04:34:02 +00001984 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001985 unsigned int written;
1986 WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
1987
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001988 switch (mid->mid_state) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001989 case MID_RESPONSE_RECEIVED:
1990 wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
1991 if (wdata->result != 0)
1992 break;
1993
1994 written = le16_to_cpu(smb->CountHigh);
1995 written <<= 16;
1996 written += le16_to_cpu(smb->Count);
1997 /*
1998 * Mask off high 16 bits when bytes written as returned
1999 * by the server is greater than bytes requested by the
2000 * client. OS/2 servers are known to set incorrect
2001 * CountHigh values.
2002 */
2003 if (written > wdata->bytes)
2004 written &= 0xFFFF;
2005
2006 if (written < wdata->bytes)
2007 wdata->result = -ENOSPC;
2008 else
2009 wdata->bytes = written;
2010 break;
2011 case MID_REQUEST_SUBMITTED:
2012 case MID_RETRY_NEEDED:
2013 wdata->result = -EAGAIN;
2014 break;
2015 default:
2016 wdata->result = -EIO;
2017 break;
2018 }
2019
Jeff Laytonda472fc2012-03-23 14:40:53 -04002020 queue_work(cifsiod_wq, &wdata->work);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002021 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002022 add_credits(tcon->ses->server, 1, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002023}
2024
2025/* cifs_async_writev - send an async write, and set up mid to handle result */
2026int
2027cifs_async_writev(struct cifs_writedata *wdata)
2028{
Jeff Laytoneddb0792012-09-18 16:20:35 -07002029 int rc = -EACCES;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002030 WRITE_REQ *smb = NULL;
2031 int wct;
Steve French96daf2b2011-05-27 04:34:02 +00002032 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytoneddb0792012-09-18 16:20:35 -07002033 struct kvec iov;
Jeff Laytonfec344e2012-09-18 16:20:35 -07002034 struct smb_rqst rqst = { };
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002035
2036 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
2037 wct = 14;
2038 } else {
2039 wct = 12;
2040 if (wdata->offset >> 32 > 0) {
2041 /* can not handle big offset for old srv */
2042 return -EIO;
2043 }
2044 }
2045
2046 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
2047 if (rc)
2048 goto async_writev_out;
2049
Jeff Laytonfe5f5d22012-03-23 14:40:55 -04002050 smb->hdr.Pid = cpu_to_le16((__u16)wdata->pid);
2051 smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16));
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002052
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002053 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07002054 smb->Fid = wdata->cfile->fid.netfid;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002055 smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
2056 if (wct == 14)
2057 smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
2058 smb->Reserved = 0xFFFFFFFF;
2059 smb->WriteMode = 0;
2060 smb->Remaining = 0;
2061
2062 smb->DataOffset =
2063 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
2064
2065 /* 4 for RFC1001 length + 1 for BCC */
Jeff Laytoneddb0792012-09-18 16:20:35 -07002066 iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4 + 1;
2067 iov.iov_base = smb;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002068
Jeff Laytoneddb0792012-09-18 16:20:35 -07002069 rqst.rq_iov = &iov;
2070 rqst.rq_nvec = 1;
2071 rqst.rq_pages = wdata->pages;
2072 rqst.rq_npages = wdata->nr_pages;
2073 rqst.rq_pagesz = wdata->pagesz;
2074 rqst.rq_tailsz = wdata->tailsz;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002075
2076 cFYI(1, "async write at %llu %u bytes", wdata->offset, wdata->bytes);
2077
2078 smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
2079 smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16);
2080
2081 if (wct == 14) {
2082 inc_rfc1001_len(&smb->hdr, wdata->bytes + 1);
2083 put_bcc(wdata->bytes + 1, &smb->hdr);
2084 } else {
2085 /* wct == 12 */
2086 struct smb_com_writex_req *smbw =
2087 (struct smb_com_writex_req *)smb;
2088 inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
2089 put_bcc(wdata->bytes + 5, &smbw->hdr);
Jeff Laytoneddb0792012-09-18 16:20:35 -07002090 iov.iov_len += 4; /* pad bigger by four bytes */
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002091 }
2092
2093 kref_get(&wdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07002094 rc = cifs_call_async(tcon->ses->server, &rqst, NULL,
2095 cifs_writev_callback, wdata, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002096
2097 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002098 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002099 else
2100 kref_put(&wdata->refcount, cifs_writedata_release);
2101
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002102async_writev_out:
2103 cifs_small_buf_release(smb);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002104 return rc;
2105}
2106
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002107int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002108CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
Pavel Shilovskyba9ad7252012-09-18 16:20:30 -07002109 unsigned int *nbytes, struct kvec *iov, int n_vec)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110{
2111 int rc = -EACCES;
2112 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08002113 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002114 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08002115 int resp_buf_type = 0;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002116 __u32 pid = io_parms->pid;
2117 __u16 netfid = io_parms->netfid;
2118 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00002119 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002120 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002121
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04002122 *nbytes = 0;
2123
Joe Perchesb6b38f72010-04-21 03:50:45 +00002124 cFYI(1, "write2 at %lld %d bytes", (long long)offset, count);
Steve Frenchff7feac2005-11-15 16:45:16 -08002125
Steve French4c3130e2008-12-09 00:28:16 +00002126 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07002127 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00002128 } else {
Steve French8cc64c62005-10-03 13:49:43 -07002129 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00002130 if ((offset >> 32) > 0) {
2131 /* can not handle big offset for old srv */
2132 return -EIO;
2133 }
2134 }
Steve French8cc64c62005-10-03 13:49:43 -07002135 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002136 if (rc)
2137 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002138
2139 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
2140 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
2141
Linus Torvalds1da177e2005-04-16 15:20:36 -07002142 /* tcon and ses pointer are checked in smb_init */
2143 if (tcon->ses->server == NULL)
2144 return -ECONNABORTED;
2145
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002146 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002147 pSMB->Fid = netfid;
2148 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00002149 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002150 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002151 pSMB->Reserved = 0xFFFFFFFF;
2152 pSMB->WriteMode = 0;
2153 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002154
Linus Torvalds1da177e2005-04-16 15:20:36 -07002155 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00002156 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002157
Steve French3e844692005-10-03 13:37:24 -07002158 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
2159 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002160 /* header + 1 byte pad */
2161 smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
Steve French790fe572007-07-07 19:25:05 +00002162 if (wct == 14)
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002163 inc_rfc1001_len(pSMB, count + 1);
Steve French8cc64c62005-10-03 13:49:43 -07002164 else /* wct == 12 */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002165 inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
Steve French790fe572007-07-07 19:25:05 +00002166 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002167 pSMB->ByteCount = cpu_to_le16(count + 1);
2168 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00002169 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07002170 (struct smb_com_writex_req *)pSMB;
2171 pSMBW->ByteCount = cpu_to_le16(count + 5);
2172 }
Steve French3e844692005-10-03 13:37:24 -07002173 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00002174 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08002175 iov[0].iov_len = smb_hdr_len + 4;
2176 else /* wct == 12 pad bigger by four bytes */
2177 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00002178
Steve French3e844692005-10-03 13:37:24 -07002179
Pavel Shilovskyba9ad7252012-09-18 16:20:30 -07002180 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002181 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002182 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002183 cFYI(1, "Send error Write2 = %d", rc);
Steve French790fe572007-07-07 19:25:05 +00002184 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08002185 /* presumably this can not happen, but best to be safe */
2186 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002187 } else {
Steve Frenchad7a2922008-02-07 23:25:02 +00002188 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002189 *nbytes = le16_to_cpu(pSMBr->CountHigh);
2190 *nbytes = (*nbytes) << 16;
2191 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05302192
2193 /*
2194 * Mask off high 16 bits when bytes written as returned by the
2195 * server is greater than bytes requested by the client. OS/2
2196 * servers are known to set incorrect CountHigh values.
2197 */
2198 if (*nbytes > count)
2199 *nbytes &= 0xFFFF;
Steve French50c2f752007-07-13 00:33:32 +00002200 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002201
Steve French4b8f9302006-02-26 16:41:18 +00002202/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00002203 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002204 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00002205 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002206 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002207
Steve French50c2f752007-07-13 00:33:32 +00002208 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002209 since file handle passed in no longer valid */
2210
2211 return rc;
2212}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002213
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002214int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon,
2215 const __u16 netfid, const __u8 lock_type, const __u32 num_unlock,
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002216 const __u32 num_lock, LOCKING_ANDX_RANGE *buf)
2217{
2218 int rc = 0;
2219 LOCK_REQ *pSMB = NULL;
2220 struct kvec iov[2];
2221 int resp_buf_type;
2222 __u16 count;
2223
2224 cFYI(1, "cifs_lockv num lock %d num unlock %d", num_lock, num_unlock);
2225
2226 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2227 if (rc)
2228 return rc;
2229
2230 pSMB->Timeout = 0;
2231 pSMB->NumberOfLocks = cpu_to_le16(num_lock);
2232 pSMB->NumberOfUnlocks = cpu_to_le16(num_unlock);
2233 pSMB->LockType = lock_type;
2234 pSMB->AndXCommand = 0xFF; /* none */
2235 pSMB->Fid = netfid; /* netfid stays le */
2236
2237 count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2238 inc_rfc1001_len(pSMB, count);
2239 pSMB->ByteCount = cpu_to_le16(count);
2240
2241 iov[0].iov_base = (char *)pSMB;
2242 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 -
2243 (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2244 iov[1].iov_base = (char *)buf;
2245 iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2246
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002247 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002248 rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP);
2249 if (rc)
2250 cFYI(1, "Send error in cifs_lockv = %d", rc);
2251
2252 return rc;
2253}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002254
Linus Torvalds1da177e2005-04-16 15:20:36 -07002255int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002256CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002257 const __u16 smb_file_id, const __u32 netpid, const __u64 len,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002258 const __u64 offset, const __u32 numUnlock,
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002259 const __u32 numLock, const __u8 lockType,
2260 const bool waitFlag, const __u8 oplock_level)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002261{
2262 int rc = 0;
2263 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002264/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002265 int bytes_returned;
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002266 int flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002267 __u16 count;
2268
Joe Perchesb6b38f72010-04-21 03:50:45 +00002269 cFYI(1, "CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock);
Steve French46810cb2005-04-28 22:41:09 -07002270 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2271
Linus Torvalds1da177e2005-04-16 15:20:36 -07002272 if (rc)
2273 return rc;
2274
Steve French790fe572007-07-07 19:25:05 +00002275 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002276 /* no response expected */
2277 flags = CIFS_ASYNC_OP | CIFS_OBREAK_OP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002278 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00002279 } else if (waitFlag) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002280 flags = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002281 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
2282 } else {
2283 pSMB->Timeout = 0;
2284 }
2285
2286 pSMB->NumberOfLocks = cpu_to_le16(numLock);
2287 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
2288 pSMB->LockType = lockType;
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002289 pSMB->OplockLevel = oplock_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002290 pSMB->AndXCommand = 0xFF; /* none */
2291 pSMB->Fid = smb_file_id; /* netfid stays le */
2292
Steve French790fe572007-07-07 19:25:05 +00002293 if ((numLock != 0) || (numUnlock != 0)) {
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002294 pSMB->Locks[0].Pid = cpu_to_le16(netpid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002295 /* BB where to store pid high? */
2296 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
2297 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
2298 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
2299 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
2300 count = sizeof(LOCKING_ANDX_RANGE);
2301 } else {
2302 /* oplock break */
2303 count = 0;
2304 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002305 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002306 pSMB->ByteCount = cpu_to_le16(count);
2307
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002308 if (waitFlag) {
2309 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002310 (struct smb_hdr *) pSMB, &bytes_returned);
Steve French133672e2007-11-13 22:41:37 +00002311 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002312 } else {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002313 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, flags);
Steve French133672e2007-11-13 22:41:37 +00002314 /* SMB buffer freed by function above */
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002315 }
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002316 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002317 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002318 cFYI(1, "Send error in Lock = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002319
Steve French50c2f752007-07-13 00:33:32 +00002320 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002321 since file handle passed in no longer valid */
2322 return rc;
2323}
2324
2325int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002326CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002327 const __u16 smb_file_id, const __u32 netpid,
2328 const loff_t start_offset, const __u64 len,
2329 struct file_lock *pLockData, const __u16 lock_type,
2330 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00002331{
2332 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2333 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00002334 struct cifs_posix_lock *parm_data;
2335 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00002336 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00002337 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00002338 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00002339 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00002340 struct kvec iov[1];
Steve French08547b02006-02-28 22:39:25 +00002341
Joe Perchesb6b38f72010-04-21 03:50:45 +00002342 cFYI(1, "Posix Lock");
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002343
Steve French08547b02006-02-28 22:39:25 +00002344 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
2345
2346 if (rc)
2347 return rc;
2348
2349 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
2350
Steve French50c2f752007-07-13 00:33:32 +00002351 params = 6;
Steve French08547b02006-02-28 22:39:25 +00002352 pSMB->MaxSetupCount = 0;
2353 pSMB->Reserved = 0;
2354 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00002355 pSMB->Reserved2 = 0;
2356 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2357 offset = param_offset + params;
2358
Steve French08547b02006-02-28 22:39:25 +00002359 count = sizeof(struct cifs_posix_lock);
2360 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002361 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00002362 pSMB->SetupCount = 1;
2363 pSMB->Reserved3 = 0;
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002364 if (pLockData)
Steve French08547b02006-02-28 22:39:25 +00002365 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2366 else
2367 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2368 byte_count = 3 /* pad */ + params + count;
2369 pSMB->DataCount = cpu_to_le16(count);
2370 pSMB->ParameterCount = cpu_to_le16(params);
2371 pSMB->TotalDataCount = pSMB->DataCount;
2372 pSMB->TotalParameterCount = pSMB->ParameterCount;
2373 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00002374 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00002375 (((char *) &pSMB->hdr.Protocol) + offset);
2376
2377 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00002378 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00002379 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00002380 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00002381 pSMB->Timeout = cpu_to_le32(-1);
2382 } else
2383 pSMB->Timeout = 0;
2384
Pavel Shilovsky4f6bcec2011-10-22 15:33:30 +04002385 parm_data->pid = cpu_to_le32(netpid);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002386 parm_data->start = cpu_to_le64(start_offset);
Steve Frenchcec6815a2006-05-30 18:07:17 +00002387 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00002388
2389 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00002390 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00002391 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
2392 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002393 inc_rfc1001_len(pSMB, byte_count);
Steve French08547b02006-02-28 22:39:25 +00002394 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002395 if (waitFlag) {
2396 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2397 (struct smb_hdr *) pSMBr, &bytes_returned);
2398 } else {
Steve French133672e2007-11-13 22:41:37 +00002399 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002400 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French133672e2007-11-13 22:41:37 +00002401 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
2402 &resp_buf_type, timeout);
2403 pSMB = NULL; /* request buf already freed by SendReceive2. Do
2404 not try to free it twice below on exit */
2405 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002406 }
2407
Steve French08547b02006-02-28 22:39:25 +00002408 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002409 cFYI(1, "Send error in Posix Lock = %d", rc);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002410 } else if (pLockData) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002411 /* lock structure can be returned on get */
2412 __u16 data_offset;
2413 __u16 data_count;
2414 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00002415
Jeff Layton820a8032011-05-04 08:05:26 -04002416 if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002417 rc = -EIO; /* bad smb */
2418 goto plk_err_exit;
2419 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002420 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2421 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00002422 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002423 rc = -EIO;
2424 goto plk_err_exit;
2425 }
2426 parm_data = (struct cifs_posix_lock *)
2427 ((char *)&pSMBr->hdr.Protocol + data_offset);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002428 if (parm_data->lock_type == __constant_cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002429 pLockData->fl_type = F_UNLCK;
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002430 else {
2431 if (parm_data->lock_type ==
2432 __constant_cpu_to_le16(CIFS_RDLCK))
2433 pLockData->fl_type = F_RDLCK;
2434 else if (parm_data->lock_type ==
2435 __constant_cpu_to_le16(CIFS_WRLCK))
2436 pLockData->fl_type = F_WRLCK;
2437
Steve French5443d132011-03-13 05:08:25 +00002438 pLockData->fl_start = le64_to_cpu(parm_data->start);
2439 pLockData->fl_end = pLockData->fl_start +
2440 le64_to_cpu(parm_data->length) - 1;
2441 pLockData->fl_pid = le32_to_cpu(parm_data->pid);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002442 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002443 }
Steve French50c2f752007-07-13 00:33:32 +00002444
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002445plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00002446 if (pSMB)
2447 cifs_small_buf_release(pSMB);
2448
Steve French133672e2007-11-13 22:41:37 +00002449 if (resp_buf_type == CIFS_SMALL_BUFFER)
2450 cifs_small_buf_release(iov[0].iov_base);
2451 else if (resp_buf_type == CIFS_LARGE_BUFFER)
2452 cifs_buf_release(iov[0].iov_base);
2453
Steve French08547b02006-02-28 22:39:25 +00002454 /* Note: On -EAGAIN error only caller can retry on handle based calls
2455 since file handle passed in no longer valid */
2456
2457 return rc;
2458}
2459
2460
2461int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002462CIFSSMBClose(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002463{
2464 int rc = 0;
2465 CLOSE_REQ *pSMB = NULL;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002466 cFYI(1, "In CIFSSMBClose");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002467
2468/* do not retry on dead session on close */
2469 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00002470 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002471 return 0;
2472 if (rc)
2473 return rc;
2474
Linus Torvalds1da177e2005-04-16 15:20:36 -07002475 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00002476 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002477 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002478 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002479 cifs_stats_inc(&tcon->stats.cifs_stats.num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002480 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00002481 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002482 /* EINTR is expected when user ctl-c to kill app */
Joe Perchesb6b38f72010-04-21 03:50:45 +00002483 cERROR(1, "Send error in Close = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002484 }
2485 }
2486
Linus Torvalds1da177e2005-04-16 15:20:36 -07002487 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00002488 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002489 rc = 0;
2490
2491 return rc;
2492}
2493
2494int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002495CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Steve Frenchb298f222009-02-21 21:17:43 +00002496{
2497 int rc = 0;
2498 FLUSH_REQ *pSMB = NULL;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002499 cFYI(1, "In CIFSSMBFlush");
Steve Frenchb298f222009-02-21 21:17:43 +00002500
2501 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
2502 if (rc)
2503 return rc;
2504
2505 pSMB->FileID = (__u16) smb_file_id;
2506 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002507 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002508 cifs_stats_inc(&tcon->stats.cifs_stats.num_flushes);
Steve Frenchb298f222009-02-21 21:17:43 +00002509 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002510 cERROR(1, "Send error in Flush = %d", rc);
Steve Frenchb298f222009-02-21 21:17:43 +00002511
2512 return rc;
2513}
2514
2515int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002516CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002517 const char *from_name, const char *to_name,
2518 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002519{
2520 int rc = 0;
2521 RENAME_REQ *pSMB = NULL;
2522 RENAME_RSP *pSMBr = NULL;
2523 int bytes_returned;
2524 int name_len, name_len2;
2525 __u16 count;
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002526 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002527
Joe Perchesb6b38f72010-04-21 03:50:45 +00002528 cFYI(1, "In CIFSSMBRename");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529renameRetry:
2530 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
2531 (void **) &pSMBr);
2532 if (rc)
2533 return rc;
2534
2535 pSMB->BufferFormat = 0x04;
2536 pSMB->SearchAttributes =
2537 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2538 ATTR_DIRECTORY);
2539
2540 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002541 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2542 from_name, PATH_MAX,
2543 cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002544 name_len++; /* trailing null */
2545 name_len *= 2;
2546 pSMB->OldFileName[name_len] = 0x04; /* pad */
2547 /* protocol requires ASCII signature byte on Unicode string */
2548 pSMB->OldFileName[name_len + 1] = 0x00;
2549 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002550 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002551 to_name, PATH_MAX, cifs_sb->local_nls,
2552 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002553 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2554 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002555 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002556 name_len = strnlen(from_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002557 name_len++; /* trailing null */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002558 strncpy(pSMB->OldFileName, from_name, name_len);
2559 name_len2 = strnlen(to_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002560 name_len2++; /* trailing null */
2561 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002562 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002563 name_len2++; /* trailing null */
2564 name_len2++; /* signature byte */
2565 }
2566
2567 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002568 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002569 pSMB->ByteCount = cpu_to_le16(count);
2570
2571 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2572 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002573 cifs_stats_inc(&tcon->stats.cifs_stats.num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002574 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002575 cFYI(1, "Send error in rename = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002576
Linus Torvalds1da177e2005-04-16 15:20:36 -07002577 cifs_buf_release(pSMB);
2578
2579 if (rc == -EAGAIN)
2580 goto renameRetry;
2581
2582 return rc;
2583}
2584
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002585int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002586 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002587 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002588{
2589 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2590 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002591 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002592 char *data_offset;
2593 char dummy_string[30];
2594 int rc = 0;
2595 int bytes_returned = 0;
2596 int len_of_str;
2597 __u16 params, param_offset, offset, count, byte_count;
2598
Joe Perchesb6b38f72010-04-21 03:50:45 +00002599 cFYI(1, "Rename to File by handle");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002600 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2601 (void **) &pSMBr);
2602 if (rc)
2603 return rc;
2604
2605 params = 6;
2606 pSMB->MaxSetupCount = 0;
2607 pSMB->Reserved = 0;
2608 pSMB->Flags = 0;
2609 pSMB->Timeout = 0;
2610 pSMB->Reserved2 = 0;
2611 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2612 offset = param_offset + params;
2613
2614 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2615 rename_info = (struct set_file_rename *) data_offset;
2616 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002617 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002618 pSMB->SetupCount = 1;
2619 pSMB->Reserved3 = 0;
2620 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2621 byte_count = 3 /* pad */ + params;
2622 pSMB->ParameterCount = cpu_to_le16(params);
2623 pSMB->TotalParameterCount = pSMB->ParameterCount;
2624 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2625 pSMB->DataOffset = cpu_to_le16(offset);
2626 /* construct random name ".cifs_tmp<inodenum><mid>" */
2627 rename_info->overwrite = cpu_to_le32(1);
2628 rename_info->root_fid = 0;
2629 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002630 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002631 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
Steve Frenchacbbb762012-01-18 22:32:33 -06002632 len_of_str =
2633 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002634 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635 } else {
Steve Frenchacbbb762012-01-18 22:32:33 -06002636 len_of_str =
2637 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002638 target_name, PATH_MAX, nls_codepage,
2639 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002640 }
2641 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002642 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002643 byte_count += count;
2644 pSMB->DataCount = cpu_to_le16(count);
2645 pSMB->TotalDataCount = pSMB->DataCount;
2646 pSMB->Fid = netfid;
2647 pSMB->InformationLevel =
2648 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2649 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002650 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651 pSMB->ByteCount = cpu_to_le16(byte_count);
2652 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002653 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002654 cifs_stats_inc(&pTcon->stats.cifs_stats.num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002655 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002656 cFYI(1, "Send error in Rename (by file handle) = %d", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07002657
Linus Torvalds1da177e2005-04-16 15:20:36 -07002658 cifs_buf_release(pSMB);
2659
2660 /* Note: On -EAGAIN error only caller can retry on handle based calls
2661 since file handle passed in no longer valid */
2662
2663 return rc;
2664}
2665
2666int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002667CIFSSMBCopy(const unsigned int xid, struct cifs_tcon *tcon,
2668 const char *fromName, const __u16 target_tid, const char *toName,
2669 const int flags, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002670{
2671 int rc = 0;
2672 COPY_REQ *pSMB = NULL;
2673 COPY_RSP *pSMBr = NULL;
2674 int bytes_returned;
2675 int name_len, name_len2;
2676 __u16 count;
2677
Joe Perchesb6b38f72010-04-21 03:50:45 +00002678 cFYI(1, "In CIFSSMBCopy");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002679copyRetry:
2680 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2681 (void **) &pSMBr);
2682 if (rc)
2683 return rc;
2684
2685 pSMB->BufferFormat = 0x04;
2686 pSMB->Tid2 = target_tid;
2687
2688 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2689
2690 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002691 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2692 fromName, PATH_MAX, nls_codepage,
2693 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002694 name_len++; /* trailing null */
2695 name_len *= 2;
2696 pSMB->OldFileName[name_len] = 0x04; /* pad */
2697 /* protocol requires ASCII signature byte on Unicode string */
2698 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002699 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002700 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2701 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002702 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2703 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002704 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002705 name_len = strnlen(fromName, PATH_MAX);
2706 name_len++; /* trailing null */
2707 strncpy(pSMB->OldFileName, fromName, name_len);
2708 name_len2 = strnlen(toName, PATH_MAX);
2709 name_len2++; /* trailing null */
2710 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2711 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2712 name_len2++; /* trailing null */
2713 name_len2++; /* signature byte */
2714 }
2715
2716 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002717 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002718 pSMB->ByteCount = cpu_to_le16(count);
2719
2720 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2721 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2722 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002723 cFYI(1, "Send error in copy = %d with %d files copied",
2724 rc, le16_to_cpu(pSMBr->CopyCount));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002725 }
Steve French0d817bc2008-05-22 02:02:03 +00002726 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002727
2728 if (rc == -EAGAIN)
2729 goto copyRetry;
2730
2731 return rc;
2732}
2733
2734int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002735CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002736 const char *fromName, const char *toName,
2737 const struct nls_table *nls_codepage)
2738{
2739 TRANSACTION2_SPI_REQ *pSMB = NULL;
2740 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2741 char *data_offset;
2742 int name_len;
2743 int name_len_target;
2744 int rc = 0;
2745 int bytes_returned = 0;
2746 __u16 params, param_offset, offset, byte_count;
2747
Joe Perchesb6b38f72010-04-21 03:50:45 +00002748 cFYI(1, "In Symlink Unix style");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002749createSymLinkRetry:
2750 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2751 (void **) &pSMBr);
2752 if (rc)
2753 return rc;
2754
2755 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2756 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06002757 cifs_strtoUTF16((__le16 *) pSMB->FileName, fromName,
2758 /* find define for this maxpathcomponent */
2759 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002760 name_len++; /* trailing null */
2761 name_len *= 2;
2762
Steve French50c2f752007-07-13 00:33:32 +00002763 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002764 name_len = strnlen(fromName, PATH_MAX);
2765 name_len++; /* trailing null */
2766 strncpy(pSMB->FileName, fromName, name_len);
2767 }
2768 params = 6 + name_len;
2769 pSMB->MaxSetupCount = 0;
2770 pSMB->Reserved = 0;
2771 pSMB->Flags = 0;
2772 pSMB->Timeout = 0;
2773 pSMB->Reserved2 = 0;
2774 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002775 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002776 offset = param_offset + params;
2777
2778 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2779 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2780 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06002781 cifs_strtoUTF16((__le16 *) data_offset, toName, PATH_MAX
2782 /* find define for this maxpathcomponent */
2783 , nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002784 name_len_target++; /* trailing null */
2785 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002786 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002787 name_len_target = strnlen(toName, PATH_MAX);
2788 name_len_target++; /* trailing null */
2789 strncpy(data_offset, toName, name_len_target);
2790 }
2791
2792 pSMB->MaxParameterCount = cpu_to_le16(2);
2793 /* BB find exact max on data count below from sess */
2794 pSMB->MaxDataCount = cpu_to_le16(1000);
2795 pSMB->SetupCount = 1;
2796 pSMB->Reserved3 = 0;
2797 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2798 byte_count = 3 /* pad */ + params + name_len_target;
2799 pSMB->DataCount = cpu_to_le16(name_len_target);
2800 pSMB->ParameterCount = cpu_to_le16(params);
2801 pSMB->TotalDataCount = pSMB->DataCount;
2802 pSMB->TotalParameterCount = pSMB->ParameterCount;
2803 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2804 pSMB->DataOffset = cpu_to_le16(offset);
2805 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2806 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002807 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002808 pSMB->ByteCount = cpu_to_le16(byte_count);
2809 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2810 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002811 cifs_stats_inc(&tcon->stats.cifs_stats.num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002812 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002813 cFYI(1, "Send error in SetPathInfo create symlink = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002814
Steve French0d817bc2008-05-22 02:02:03 +00002815 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002816
2817 if (rc == -EAGAIN)
2818 goto createSymLinkRetry;
2819
2820 return rc;
2821}
2822
2823int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002824CIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002825 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002826 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002827{
2828 TRANSACTION2_SPI_REQ *pSMB = NULL;
2829 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2830 char *data_offset;
2831 int name_len;
2832 int name_len_target;
2833 int rc = 0;
2834 int bytes_returned = 0;
2835 __u16 params, param_offset, offset, byte_count;
2836
Joe Perchesb6b38f72010-04-21 03:50:45 +00002837 cFYI(1, "In Create Hard link Unix style");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002838createHardLinkRetry:
2839 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2840 (void **) &pSMBr);
2841 if (rc)
2842 return rc;
2843
2844 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002845 name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, toName,
2846 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002847 name_len++; /* trailing null */
2848 name_len *= 2;
2849
Steve French50c2f752007-07-13 00:33:32 +00002850 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002851 name_len = strnlen(toName, PATH_MAX);
2852 name_len++; /* trailing null */
2853 strncpy(pSMB->FileName, toName, name_len);
2854 }
2855 params = 6 + name_len;
2856 pSMB->MaxSetupCount = 0;
2857 pSMB->Reserved = 0;
2858 pSMB->Flags = 0;
2859 pSMB->Timeout = 0;
2860 pSMB->Reserved2 = 0;
2861 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002862 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002863 offset = param_offset + params;
2864
2865 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2866 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2867 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06002868 cifsConvertToUTF16((__le16 *) data_offset, fromName,
2869 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002870 name_len_target++; /* trailing null */
2871 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002872 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002873 name_len_target = strnlen(fromName, PATH_MAX);
2874 name_len_target++; /* trailing null */
2875 strncpy(data_offset, fromName, name_len_target);
2876 }
2877
2878 pSMB->MaxParameterCount = cpu_to_le16(2);
2879 /* BB find exact max on data count below from sess*/
2880 pSMB->MaxDataCount = cpu_to_le16(1000);
2881 pSMB->SetupCount = 1;
2882 pSMB->Reserved3 = 0;
2883 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2884 byte_count = 3 /* pad */ + params + name_len_target;
2885 pSMB->ParameterCount = cpu_to_le16(params);
2886 pSMB->TotalParameterCount = pSMB->ParameterCount;
2887 pSMB->DataCount = cpu_to_le16(name_len_target);
2888 pSMB->TotalDataCount = pSMB->DataCount;
2889 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2890 pSMB->DataOffset = cpu_to_le16(offset);
2891 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2892 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002893 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002894 pSMB->ByteCount = cpu_to_le16(byte_count);
2895 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2896 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002897 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002898 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002899 cFYI(1, "Send error in SetPathInfo (hard link) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002900
2901 cifs_buf_release(pSMB);
2902 if (rc == -EAGAIN)
2903 goto createHardLinkRetry;
2904
2905 return rc;
2906}
2907
2908int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002909CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchd6e906f2012-09-18 16:20:31 -07002910 const char *from_name, const char *to_name,
2911 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002912{
2913 int rc = 0;
2914 NT_RENAME_REQ *pSMB = NULL;
2915 RENAME_RSP *pSMBr = NULL;
2916 int bytes_returned;
2917 int name_len, name_len2;
2918 __u16 count;
Steve Frenchd6e906f2012-09-18 16:20:31 -07002919 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002920
Joe Perchesb6b38f72010-04-21 03:50:45 +00002921 cFYI(1, "In CIFSCreateHardLink");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002922winCreateHardLinkRetry:
2923
2924 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2925 (void **) &pSMBr);
2926 if (rc)
2927 return rc;
2928
2929 pSMB->SearchAttributes =
2930 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2931 ATTR_DIRECTORY);
2932 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2933 pSMB->ClusterCount = 0;
2934
2935 pSMB->BufferFormat = 0x04;
2936
2937 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2938 name_len =
Steve Frenchd6e906f2012-09-18 16:20:31 -07002939 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, from_name,
2940 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002941 name_len++; /* trailing null */
2942 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05002943
2944 /* protocol specifies ASCII buffer format (0x04) for unicode */
2945 pSMB->OldFileName[name_len] = 0x04;
2946 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002947 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002948 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Steve Frenchd6e906f2012-09-18 16:20:31 -07002949 to_name, PATH_MAX, cifs_sb->local_nls,
2950 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002951 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2952 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002953 } else { /* BB improve the check for buffer overruns BB */
Steve Frenchd6e906f2012-09-18 16:20:31 -07002954 name_len = strnlen(from_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002955 name_len++; /* trailing null */
Steve Frenchd6e906f2012-09-18 16:20:31 -07002956 strncpy(pSMB->OldFileName, from_name, name_len);
2957 name_len2 = strnlen(to_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002958 name_len2++; /* trailing null */
2959 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Steve Frenchd6e906f2012-09-18 16:20:31 -07002960 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002961 name_len2++; /* trailing null */
2962 name_len2++; /* signature byte */
2963 }
2964
2965 count = 1 /* string type byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002966 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002967 pSMB->ByteCount = cpu_to_le16(count);
2968
2969 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2970 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002971 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002972 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002973 cFYI(1, "Send error in hard link (NT rename) = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00002974
Linus Torvalds1da177e2005-04-16 15:20:36 -07002975 cifs_buf_release(pSMB);
2976 if (rc == -EAGAIN)
2977 goto winCreateHardLinkRetry;
2978
2979 return rc;
2980}
2981
2982int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002983CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04002984 const unsigned char *searchName, char **symlinkinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002985 const struct nls_table *nls_codepage)
2986{
2987/* SMB_QUERY_FILE_UNIX_LINK */
2988 TRANSACTION2_QPI_REQ *pSMB = NULL;
2989 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2990 int rc = 0;
2991 int bytes_returned;
2992 int name_len;
2993 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04002994 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002995
Joe Perchesb6b38f72010-04-21 03:50:45 +00002996 cFYI(1, "In QPathSymLinkInfo (Unix) for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002997
2998querySymLinkRetry:
2999 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3000 (void **) &pSMBr);
3001 if (rc)
3002 return rc;
3003
3004 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3005 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003006 cifs_strtoUTF16((__le16 *) pSMB->FileName, searchName,
3007 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003008 name_len++; /* trailing null */
3009 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003010 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003011 name_len = strnlen(searchName, PATH_MAX);
3012 name_len++; /* trailing null */
3013 strncpy(pSMB->FileName, searchName, name_len);
3014 }
3015
3016 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3017 pSMB->TotalDataCount = 0;
3018 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04003019 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003020 pSMB->MaxSetupCount = 0;
3021 pSMB->Reserved = 0;
3022 pSMB->Flags = 0;
3023 pSMB->Timeout = 0;
3024 pSMB->Reserved2 = 0;
3025 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003026 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003027 pSMB->DataCount = 0;
3028 pSMB->DataOffset = 0;
3029 pSMB->SetupCount = 1;
3030 pSMB->Reserved3 = 0;
3031 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3032 byte_count = params + 1 /* pad */ ;
3033 pSMB->TotalParameterCount = cpu_to_le16(params);
3034 pSMB->ParameterCount = pSMB->TotalParameterCount;
3035 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
3036 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003037 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003038 pSMB->ByteCount = cpu_to_le16(byte_count);
3039
3040 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3041 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3042 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003043 cFYI(1, "Send error in QuerySymLinkInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003044 } else {
3045 /* decode response */
3046
3047 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003048 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003049 if (rc || get_bcc(&pSMBr->hdr) < 2)
Jeff Layton460b9692009-04-30 07:17:56 -04003050 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003051 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00003052 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04003053 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003054
Jeff Layton460b9692009-04-30 07:17:56 -04003055 data_start = ((char *) &pSMBr->hdr.Protocol) +
3056 le16_to_cpu(pSMBr->t2.DataOffset);
3057
Steve French0e0d2cf2009-05-01 05:27:32 +00003058 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3059 is_unicode = true;
3060 else
3061 is_unicode = false;
3062
Steve French737b7582005-04-28 22:41:06 -07003063 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchacbbb762012-01-18 22:32:33 -06003064 *symlinkinfo = cifs_strndup_from_utf16(data_start,
3065 count, is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04003066 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04003067 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003068 }
3069 }
3070 cifs_buf_release(pSMB);
3071 if (rc == -EAGAIN)
3072 goto querySymLinkRetry;
3073 return rc;
3074}
3075
Steve Frenchc52a95542011-02-24 06:16:22 +00003076#ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL
3077/*
3078 * Recent Windows versions now create symlinks more frequently
3079 * and they use the "reparse point" mechanism below. We can of course
3080 * do symlinks nicely to Samba and other servers which support the
3081 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
3082 * "MF" symlinks optionally, but for recent Windows we really need to
3083 * reenable the code below and fix the cifs_symlink callers to handle this.
3084 * In the interim this code has been moved to its own config option so
3085 * it is not compiled in by default until callers fixed up and more tested.
3086 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003087int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003088CIFSSMBQueryReparseLinkInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003089 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00003090 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003091 const struct nls_table *nls_codepage)
3092{
3093 int rc = 0;
3094 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00003095 struct smb_com_transaction_ioctl_req *pSMB;
3096 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003097
Joe Perchesb6b38f72010-04-21 03:50:45 +00003098 cFYI(1, "In Windows reparse style QueryLink for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003099 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3100 (void **) &pSMBr);
3101 if (rc)
3102 return rc;
3103
3104 pSMB->TotalParameterCount = 0 ;
3105 pSMB->TotalDataCount = 0;
3106 pSMB->MaxParameterCount = cpu_to_le32(2);
3107 /* BB find exact data count max from sess structure BB */
Jeff Laytonc974bef2011-10-11 06:41:32 -04003108 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003109 pSMB->MaxSetupCount = 4;
3110 pSMB->Reserved = 0;
3111 pSMB->ParameterOffset = 0;
3112 pSMB->DataCount = 0;
3113 pSMB->DataOffset = 0;
3114 pSMB->SetupCount = 4;
3115 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
3116 pSMB->ParameterCount = pSMB->TotalParameterCount;
3117 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
3118 pSMB->IsFsctl = 1; /* FSCTL */
3119 pSMB->IsRootFlag = 0;
3120 pSMB->Fid = fid; /* file handle always le */
3121 pSMB->ByteCount = 0;
3122
3123 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3124 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3125 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003126 cFYI(1, "Send error in QueryReparseLinkInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003127 } else { /* decode response */
3128 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
3129 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
Jeff Layton820a8032011-05-04 08:05:26 -04003130 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
3131 /* BB also check enough total bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003132 rc = -EIO; /* bad smb */
Steve Frenchafe48c32009-05-02 05:25:46 +00003133 goto qreparse_out;
3134 }
3135 if (data_count && (data_count < 2048)) {
3136 char *end_of_smb = 2 /* sizeof byte count */ +
Jeff Layton820a8032011-05-04 08:05:26 -04003137 get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003138
Steve Frenchafe48c32009-05-02 05:25:46 +00003139 struct reparse_data *reparse_buf =
Steve French50c2f752007-07-13 00:33:32 +00003140 (struct reparse_data *)
3141 ((char *)&pSMBr->hdr.Protocol
3142 + data_offset);
Steve Frenchafe48c32009-05-02 05:25:46 +00003143 if ((char *)reparse_buf >= end_of_smb) {
3144 rc = -EIO;
3145 goto qreparse_out;
3146 }
3147 if ((reparse_buf->LinkNamesBuf +
3148 reparse_buf->TargetNameOffset +
3149 reparse_buf->TargetNameLen) > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003150 cFYI(1, "reparse buf beyond SMB");
Steve Frenchafe48c32009-05-02 05:25:46 +00003151 rc = -EIO;
3152 goto qreparse_out;
3153 }
Steve French50c2f752007-07-13 00:33:32 +00003154
Steve Frenchafe48c32009-05-02 05:25:46 +00003155 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3156 cifs_from_ucs2(symlinkinfo, (__le16 *)
Steve French50c2f752007-07-13 00:33:32 +00003157 (reparse_buf->LinkNamesBuf +
3158 reparse_buf->TargetNameOffset),
Steve Frenchafe48c32009-05-02 05:25:46 +00003159 buflen,
3160 reparse_buf->TargetNameLen,
3161 nls_codepage, 0);
3162 } else { /* ASCII names */
3163 strncpy(symlinkinfo,
3164 reparse_buf->LinkNamesBuf +
3165 reparse_buf->TargetNameOffset,
3166 min_t(const int, buflen,
3167 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003168 }
Steve Frenchafe48c32009-05-02 05:25:46 +00003169 } else {
3170 rc = -EIO;
Joe Perchesb6b38f72010-04-21 03:50:45 +00003171 cFYI(1, "Invalid return data count on "
3172 "get reparse info ioctl");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003173 }
Steve Frenchafe48c32009-05-02 05:25:46 +00003174 symlinkinfo[buflen] = 0; /* just in case so the caller
3175 does not go off the end of the buffer */
Joe Perchesb6b38f72010-04-21 03:50:45 +00003176 cFYI(1, "readlink result - %s", symlinkinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003177 }
Steve French989c7e52009-05-02 05:32:20 +00003178
Linus Torvalds1da177e2005-04-16 15:20:36 -07003179qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07003180 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003181
3182 /* Note: On -EAGAIN error only caller can retry on handle based calls
3183 since file handle passed in no longer valid */
3184
3185 return rc;
3186}
Steve Frenchc52a95542011-02-24 06:16:22 +00003187#endif /* CIFS_SYMLINK_EXPERIMENTAL */ /* BB temporarily unused */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003188
3189#ifdef CONFIG_CIFS_POSIX
3190
3191/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00003192static void cifs_convert_ace(posix_acl_xattr_entry *ace,
3193 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003194{
3195 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08003196 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
3197 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
3198 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesb6b38f72010-04-21 03:50:45 +00003199 /* cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003200
3201 return;
3202}
3203
3204/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00003205static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
3206 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003207{
3208 int size = 0;
3209 int i;
3210 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00003211 struct cifs_posix_ace *pACE;
3212 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
3213 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003214
3215 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
3216 return -EOPNOTSUPP;
3217
Steve French790fe572007-07-07 19:25:05 +00003218 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003219 count = le16_to_cpu(cifs_acl->access_entry_count);
3220 pACE = &cifs_acl->ace_array[0];
3221 size = sizeof(struct cifs_posix_acl);
3222 size += sizeof(struct cifs_posix_ace) * count;
3223 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003224 if (size_of_data_area < size) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003225 cFYI(1, "bad CIFS POSIX ACL size %d vs. %d",
3226 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003227 return -EINVAL;
3228 }
Steve French790fe572007-07-07 19:25:05 +00003229 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003230 count = le16_to_cpu(cifs_acl->access_entry_count);
3231 size = sizeof(struct cifs_posix_acl);
3232 size += sizeof(struct cifs_posix_ace) * count;
3233/* skip past access ACEs to get to default ACEs */
3234 pACE = &cifs_acl->ace_array[count];
3235 count = le16_to_cpu(cifs_acl->default_entry_count);
3236 size += sizeof(struct cifs_posix_ace) * count;
3237 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003238 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003239 return -EINVAL;
3240 } else {
3241 /* illegal type */
3242 return -EINVAL;
3243 }
3244
3245 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00003246 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00003247 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00003248 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003249 return -ERANGE;
3250 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08003251 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00003252 for (i = 0; i < count ; i++) {
3253 cifs_convert_ace(&local_acl->a_entries[i], pACE);
3254 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003255 }
3256 }
3257 return size;
3258}
3259
Steve French50c2f752007-07-13 00:33:32 +00003260static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
3261 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003262{
3263 __u16 rc = 0; /* 0 = ACL converted ok */
3264
Steve Frenchff7feac2005-11-15 16:45:16 -08003265 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
3266 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003267 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00003268 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003269 /* Probably no need to le convert -1 on any arch but can not hurt */
3270 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00003271 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08003272 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesb6b38f72010-04-21 03:50:45 +00003273 /*cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id);*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003274 return rc;
3275}
3276
3277/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00003278static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
3279 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003280{
3281 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00003282 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
3283 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003284 int count;
3285 int i;
3286
Steve French790fe572007-07-07 19:25:05 +00003287 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003288 return 0;
3289
3290 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesb6b38f72010-04-21 03:50:45 +00003291 cFYI(1, "setting acl with %d entries from buf of length %d and "
Steve French63135e02007-07-17 17:34:02 +00003292 "version of %d",
Joe Perchesb6b38f72010-04-21 03:50:45 +00003293 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00003294 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003295 cFYI(1, "unknown POSIX ACL version %d",
3296 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003297 return 0;
3298 }
3299 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00003300 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08003301 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00003302 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08003303 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003304 else {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003305 cFYI(1, "unknown ACL type %d", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003306 return 0;
3307 }
Steve French50c2f752007-07-13 00:33:32 +00003308 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003309 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
3310 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00003311 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003312 /* ACE not converted */
3313 break;
3314 }
3315 }
Steve French790fe572007-07-07 19:25:05 +00003316 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003317 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
3318 rc += sizeof(struct cifs_posix_acl);
3319 /* BB add check to make sure ACL does not overflow SMB */
3320 }
3321 return rc;
3322}
3323
3324int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003325CIFSSMBGetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003326 const unsigned char *searchName,
3327 char *acl_inf, const int buflen, const int acl_type,
3328 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003329{
3330/* SMB_QUERY_POSIX_ACL */
3331 TRANSACTION2_QPI_REQ *pSMB = NULL;
3332 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3333 int rc = 0;
3334 int bytes_returned;
3335 int name_len;
3336 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00003337
Joe Perchesb6b38f72010-04-21 03:50:45 +00003338 cFYI(1, "In GetPosixACL (Unix) for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003339
3340queryAclRetry:
3341 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3342 (void **) &pSMBr);
3343 if (rc)
3344 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003345
Linus Torvalds1da177e2005-04-16 15:20:36 -07003346 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3347 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003348 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3349 searchName, PATH_MAX, nls_codepage,
3350 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003351 name_len++; /* trailing null */
3352 name_len *= 2;
3353 pSMB->FileName[name_len] = 0;
3354 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00003355 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003356 name_len = strnlen(searchName, PATH_MAX);
3357 name_len++; /* trailing null */
3358 strncpy(pSMB->FileName, searchName, name_len);
3359 }
3360
3361 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3362 pSMB->TotalDataCount = 0;
3363 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00003364 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003365 pSMB->MaxDataCount = cpu_to_le16(4000);
3366 pSMB->MaxSetupCount = 0;
3367 pSMB->Reserved = 0;
3368 pSMB->Flags = 0;
3369 pSMB->Timeout = 0;
3370 pSMB->Reserved2 = 0;
3371 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003372 offsetof(struct smb_com_transaction2_qpi_req,
3373 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003374 pSMB->DataCount = 0;
3375 pSMB->DataOffset = 0;
3376 pSMB->SetupCount = 1;
3377 pSMB->Reserved3 = 0;
3378 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3379 byte_count = params + 1 /* pad */ ;
3380 pSMB->TotalParameterCount = cpu_to_le16(params);
3381 pSMB->ParameterCount = pSMB->TotalParameterCount;
3382 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
3383 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003384 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003385 pSMB->ByteCount = cpu_to_le16(byte_count);
3386
3387 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3388 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003389 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003390 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003391 cFYI(1, "Send error in Query POSIX ACL = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003392 } else {
3393 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00003394
Linus Torvalds1da177e2005-04-16 15:20:36 -07003395 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003396 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003397 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003398 rc = -EIO; /* bad smb */
3399 else {
3400 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3401 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3402 rc = cifs_copy_posix_acl(acl_inf,
3403 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00003404 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003405 }
3406 }
3407 cifs_buf_release(pSMB);
3408 if (rc == -EAGAIN)
3409 goto queryAclRetry;
3410 return rc;
3411}
3412
3413int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003414CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003415 const unsigned char *fileName,
3416 const char *local_acl, const int buflen,
3417 const int acl_type,
3418 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003419{
3420 struct smb_com_transaction2_spi_req *pSMB = NULL;
3421 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3422 char *parm_data;
3423 int name_len;
3424 int rc = 0;
3425 int bytes_returned = 0;
3426 __u16 params, byte_count, data_count, param_offset, offset;
3427
Joe Perchesb6b38f72010-04-21 03:50:45 +00003428 cFYI(1, "In SetPosixACL (Unix) for path %s", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003429setAclRetry:
3430 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003431 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003432 if (rc)
3433 return rc;
3434 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3435 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003436 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
3437 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003438 name_len++; /* trailing null */
3439 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003440 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003441 name_len = strnlen(fileName, PATH_MAX);
3442 name_len++; /* trailing null */
3443 strncpy(pSMB->FileName, fileName, name_len);
3444 }
3445 params = 6 + name_len;
3446 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003447 /* BB find max SMB size from sess */
3448 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003449 pSMB->MaxSetupCount = 0;
3450 pSMB->Reserved = 0;
3451 pSMB->Flags = 0;
3452 pSMB->Timeout = 0;
3453 pSMB->Reserved2 = 0;
3454 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003455 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003456 offset = param_offset + params;
3457 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
3458 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3459
3460 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00003461 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003462
Steve French790fe572007-07-07 19:25:05 +00003463 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003464 rc = -EOPNOTSUPP;
3465 goto setACLerrorExit;
3466 }
3467 pSMB->DataOffset = cpu_to_le16(offset);
3468 pSMB->SetupCount = 1;
3469 pSMB->Reserved3 = 0;
3470 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3471 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
3472 byte_count = 3 /* pad */ + params + data_count;
3473 pSMB->DataCount = cpu_to_le16(data_count);
3474 pSMB->TotalDataCount = pSMB->DataCount;
3475 pSMB->ParameterCount = cpu_to_le16(params);
3476 pSMB->TotalParameterCount = pSMB->ParameterCount;
3477 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003478 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003479 pSMB->ByteCount = cpu_to_le16(byte_count);
3480 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003481 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003482 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003483 cFYI(1, "Set POSIX ACL returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003484
3485setACLerrorExit:
3486 cifs_buf_release(pSMB);
3487 if (rc == -EAGAIN)
3488 goto setAclRetry;
3489 return rc;
3490}
3491
Steve Frenchf654bac2005-04-28 22:41:04 -07003492/* BB fix tabs in this function FIXME BB */
3493int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003494CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00003495 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07003496{
Steve French50c2f752007-07-13 00:33:32 +00003497 int rc = 0;
3498 struct smb_t2_qfi_req *pSMB = NULL;
3499 struct smb_t2_qfi_rsp *pSMBr = NULL;
3500 int bytes_returned;
3501 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07003502
Joe Perchesb6b38f72010-04-21 03:50:45 +00003503 cFYI(1, "In GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00003504 if (tcon == NULL)
3505 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07003506
3507GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003508 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3509 (void **) &pSMBr);
3510 if (rc)
3511 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003512
Steve Frenchad7a2922008-02-07 23:25:02 +00003513 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003514 pSMB->t2.TotalDataCount = 0;
3515 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3516 /* BB find exact max data count below from sess structure BB */
3517 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3518 pSMB->t2.MaxSetupCount = 0;
3519 pSMB->t2.Reserved = 0;
3520 pSMB->t2.Flags = 0;
3521 pSMB->t2.Timeout = 0;
3522 pSMB->t2.Reserved2 = 0;
3523 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3524 Fid) - 4);
3525 pSMB->t2.DataCount = 0;
3526 pSMB->t2.DataOffset = 0;
3527 pSMB->t2.SetupCount = 1;
3528 pSMB->t2.Reserved3 = 0;
3529 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3530 byte_count = params + 1 /* pad */ ;
3531 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3532 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3533 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3534 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003535 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003536 inc_rfc1001_len(pSMB, byte_count);
Steve French790fe572007-07-07 19:25:05 +00003537 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003538
Steve French790fe572007-07-07 19:25:05 +00003539 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3540 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3541 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003542 cFYI(1, "error %d in GetExtAttr", rc);
Steve French790fe572007-07-07 19:25:05 +00003543 } else {
3544 /* decode response */
3545 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003546 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003547 if (rc || get_bcc(&pSMBr->hdr) < 2)
Steve French790fe572007-07-07 19:25:05 +00003548 /* If rc should we check for EOPNOSUPP and
3549 disable the srvino flag? or in caller? */
3550 rc = -EIO; /* bad smb */
3551 else {
3552 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3553 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3554 struct file_chattr_info *pfinfo;
3555 /* BB Do we need a cast or hash here ? */
3556 if (count != 16) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003557 cFYI(1, "Illegal size ret in GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00003558 rc = -EIO;
3559 goto GetExtAttrOut;
3560 }
3561 pfinfo = (struct file_chattr_info *)
3562 (data_offset + (char *) &pSMBr->hdr.Protocol);
3563 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003564 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003565 }
3566 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003567GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003568 cifs_buf_release(pSMB);
3569 if (rc == -EAGAIN)
3570 goto GetExtAttrRetry;
3571 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003572}
3573
Steve Frenchf654bac2005-04-28 22:41:04 -07003574#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003575
Jeff Layton79df1ba2010-12-06 12:52:08 -05003576#ifdef CONFIG_CIFS_ACL
3577/*
3578 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3579 * all NT TRANSACTS that we init here have total parm and data under about 400
3580 * bytes (to fit in small cifs buffer size), which is the case so far, it
3581 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3582 * returned setup area) and MaxParameterCount (returned parms size) must be set
3583 * by caller
3584 */
3585static int
3586smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French96daf2b2011-05-27 04:34:02 +00003587 const int parm_len, struct cifs_tcon *tcon,
Jeff Layton79df1ba2010-12-06 12:52:08 -05003588 void **ret_buf)
3589{
3590 int rc;
3591 __u32 temp_offset;
3592 struct smb_com_ntransact_req *pSMB;
3593
3594 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3595 (void **)&pSMB);
3596 if (rc)
3597 return rc;
3598 *ret_buf = (void *)pSMB;
3599 pSMB->Reserved = 0;
3600 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3601 pSMB->TotalDataCount = 0;
Jeff Laytonc974bef2011-10-11 06:41:32 -04003602 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003603 pSMB->ParameterCount = pSMB->TotalParameterCount;
3604 pSMB->DataCount = pSMB->TotalDataCount;
3605 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3606 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3607 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3608 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3609 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3610 pSMB->SubCommand = cpu_to_le16(sub_command);
3611 return 0;
3612}
3613
3614static int
3615validate_ntransact(char *buf, char **ppparm, char **ppdata,
3616 __u32 *pparmlen, __u32 *pdatalen)
3617{
3618 char *end_of_smb;
3619 __u32 data_count, data_offset, parm_count, parm_offset;
3620 struct smb_com_ntransact_rsp *pSMBr;
Jeff Layton820a8032011-05-04 08:05:26 -04003621 u16 bcc;
Jeff Layton79df1ba2010-12-06 12:52:08 -05003622
3623 *pdatalen = 0;
3624 *pparmlen = 0;
3625
3626 if (buf == NULL)
3627 return -EINVAL;
3628
3629 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3630
Jeff Layton820a8032011-05-04 08:05:26 -04003631 bcc = get_bcc(&pSMBr->hdr);
3632 end_of_smb = 2 /* sizeof byte count */ + bcc +
Jeff Layton79df1ba2010-12-06 12:52:08 -05003633 (char *)&pSMBr->ByteCount;
3634
3635 data_offset = le32_to_cpu(pSMBr->DataOffset);
3636 data_count = le32_to_cpu(pSMBr->DataCount);
3637 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3638 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3639
3640 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3641 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3642
3643 /* should we also check that parm and data areas do not overlap? */
3644 if (*ppparm > end_of_smb) {
3645 cFYI(1, "parms start after end of smb");
3646 return -EINVAL;
3647 } else if (parm_count + *ppparm > end_of_smb) {
3648 cFYI(1, "parm end after end of smb");
3649 return -EINVAL;
3650 } else if (*ppdata > end_of_smb) {
3651 cFYI(1, "data starts after end of smb");
3652 return -EINVAL;
3653 } else if (data_count + *ppdata > end_of_smb) {
3654 cFYI(1, "data %p + count %d (%p) past smb end %p start %p",
3655 *ppdata, data_count, (data_count + *ppdata),
3656 end_of_smb, pSMBr);
3657 return -EINVAL;
Jeff Layton820a8032011-05-04 08:05:26 -04003658 } else if (parm_count + data_count > bcc) {
Jeff Layton79df1ba2010-12-06 12:52:08 -05003659 cFYI(1, "parm count and data count larger than SMB");
3660 return -EINVAL;
3661 }
3662 *pdatalen = data_count;
3663 *pparmlen = parm_count;
3664 return 0;
3665}
3666
Steve French0a4b92c2006-01-12 15:44:21 -08003667/* Get Security Descriptor (by handle) from remote server for a file or dir */
3668int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003669CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003670 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003671{
3672 int rc = 0;
3673 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003674 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003675 struct kvec iov[1];
3676
Joe Perchesb6b38f72010-04-21 03:50:45 +00003677 cFYI(1, "GetCifsACL");
Steve French0a4b92c2006-01-12 15:44:21 -08003678
Steve French630f3f0c2007-10-25 21:17:17 +00003679 *pbuflen = 0;
3680 *acl_inf = NULL;
3681
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003682 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003683 8 /* parm len */, tcon, (void **) &pSMB);
3684 if (rc)
3685 return rc;
3686
3687 pSMB->MaxParameterCount = cpu_to_le32(4);
3688 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3689 pSMB->MaxSetupCount = 0;
3690 pSMB->Fid = fid; /* file handle always le */
3691 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3692 CIFS_ACL_DACL);
3693 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003694 inc_rfc1001_len(pSMB, 11);
Steve French0a4b92c2006-01-12 15:44:21 -08003695 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003696 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French0a4b92c2006-01-12 15:44:21 -08003697
Steve Frencha761ac52007-10-18 21:45:27 +00003698 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Jeff Layton77499812011-01-11 07:24:23 -05003699 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003700 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Steve French0a4b92c2006-01-12 15:44:21 -08003701 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003702 cFYI(1, "Send error in QuerySecDesc = %d", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08003703 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003704 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003705 __u32 parm_len;
3706 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003707 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003708 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003709
3710/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003711 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003712 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003713 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003714 goto qsec_out;
3715 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3716
Joe Perchesb6b38f72010-04-21 03:50:45 +00003717 cFYI(1, "smb %p parm %p data %p", pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08003718
3719 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3720 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003721 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003722 goto qsec_out;
3723 }
3724
3725/* BB check that data area is minimum length and as big as acl_len */
3726
Steve Frenchaf6f4612007-10-16 18:40:37 +00003727 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003728 if (acl_len != *pbuflen) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003729 cERROR(1, "acl length %d does not match %d",
3730 acl_len, *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003731 if (*pbuflen > acl_len)
3732 *pbuflen = acl_len;
3733 }
Steve French0a4b92c2006-01-12 15:44:21 -08003734
Steve French630f3f0c2007-10-25 21:17:17 +00003735 /* check if buffer is big enough for the acl
3736 header followed by the smallest SID */
3737 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3738 (*pbuflen >= 64 * 1024)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003739 cERROR(1, "bad acl length %d", *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003740 rc = -EINVAL;
3741 *pbuflen = 0;
3742 } else {
3743 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3744 if (*acl_inf == NULL) {
3745 *pbuflen = 0;
3746 rc = -ENOMEM;
3747 }
3748 memcpy(*acl_inf, pdata, *pbuflen);
3749 }
Steve French0a4b92c2006-01-12 15:44:21 -08003750 }
3751qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003752 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003753 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003754 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003755 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003756/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003757 return rc;
3758}
Steve French97837582007-12-31 07:47:21 +00003759
3760int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003761CIFSSMBSetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003762 struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
Steve French97837582007-12-31 07:47:21 +00003763{
3764 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3765 int rc = 0;
3766 int bytes_returned = 0;
3767 SET_SEC_DESC_REQ *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003768 void *pSMBr;
Steve French97837582007-12-31 07:47:21 +00003769
3770setCifsAclRetry:
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003771 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, &pSMBr);
Steve French97837582007-12-31 07:47:21 +00003772 if (rc)
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003773 return rc;
Steve French97837582007-12-31 07:47:21 +00003774
3775 pSMB->MaxSetupCount = 0;
3776 pSMB->Reserved = 0;
3777
3778 param_count = 8;
3779 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3780 data_count = acllen;
3781 data_offset = param_offset + param_count;
3782 byte_count = 3 /* pad */ + param_count;
3783
3784 pSMB->DataCount = cpu_to_le32(data_count);
3785 pSMB->TotalDataCount = pSMB->DataCount;
3786 pSMB->MaxParameterCount = cpu_to_le32(4);
3787 pSMB->MaxDataCount = cpu_to_le32(16384);
3788 pSMB->ParameterCount = cpu_to_le32(param_count);
3789 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3790 pSMB->TotalParameterCount = pSMB->ParameterCount;
3791 pSMB->DataOffset = cpu_to_le32(data_offset);
3792 pSMB->SetupCount = 0;
3793 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3794 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3795
3796 pSMB->Fid = fid; /* file handle always le */
3797 pSMB->Reserved2 = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003798 pSMB->AclFlags = cpu_to_le32(aclflag);
Steve French97837582007-12-31 07:47:21 +00003799
3800 if (pntsd && acllen) {
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003801 memcpy((char *)pSMBr + offsetof(struct smb_hdr, Protocol) +
3802 data_offset, pntsd, acllen);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003803 inc_rfc1001_len(pSMB, byte_count + data_count);
Steve French97837582007-12-31 07:47:21 +00003804 } else
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003805 inc_rfc1001_len(pSMB, byte_count);
Steve French97837582007-12-31 07:47:21 +00003806
3807 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3808 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3809
Joe Perchesb6b38f72010-04-21 03:50:45 +00003810 cFYI(1, "SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00003811 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003812 cFYI(1, "Set CIFS ACL returned %d", rc);
Steve French97837582007-12-31 07:47:21 +00003813 cifs_buf_release(pSMB);
3814
3815 if (rc == -EAGAIN)
3816 goto setCifsAclRetry;
3817
3818 return (rc);
3819}
3820
Jeff Layton79df1ba2010-12-06 12:52:08 -05003821#endif /* CONFIG_CIFS_ACL */
Steve French0a4b92c2006-01-12 15:44:21 -08003822
Steve French6b8edfe2005-08-23 20:26:03 -07003823/* Legacy Query Path Information call for lookup to old servers such
3824 as Win9x/WinME */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003825int
3826SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon,
3827 const char *search_name, FILE_ALL_INFO *data,
3828 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003829{
Steve Frenchad7a2922008-02-07 23:25:02 +00003830 QUERY_INFORMATION_REQ *pSMB;
3831 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003832 int rc = 0;
3833 int bytes_returned;
3834 int name_len;
3835
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003836 cFYI(1, "In SMBQPath path %s", search_name);
Steve French6b8edfe2005-08-23 20:26:03 -07003837QInfRetry:
3838 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003839 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003840 if (rc)
3841 return rc;
3842
3843 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3844 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003845 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003846 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06003847 remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003848 name_len++; /* trailing null */
3849 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003850 } else {
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003851 name_len = strnlen(search_name, PATH_MAX);
Steve French6b8edfe2005-08-23 20:26:03 -07003852 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003853 strncpy(pSMB->FileName, search_name, name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07003854 }
3855 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003856 name_len++; /* account for buffer type byte */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003857 inc_rfc1001_len(pSMB, (__u16)name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07003858 pSMB->ByteCount = cpu_to_le16(name_len);
3859
3860 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003861 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003862 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003863 cFYI(1, "Send error in QueryInfo = %d", rc);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003864 } else if (data) {
Steve French1bd5bbc2006-09-28 03:35:57 +00003865 struct timespec ts;
3866 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00003867
3868 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003869 /* BB FIXME - add time zone adjustment BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003870 memset(data, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003871 ts.tv_nsec = 0;
3872 ts.tv_sec = time;
3873 /* decode time fields */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003874 data->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
3875 data->LastWriteTime = data->ChangeTime;
3876 data->LastAccessTime = 0;
3877 data->AllocationSize =
Steve French70ca7342005-09-22 16:32:06 -07003878 cpu_to_le64(le32_to_cpu(pSMBr->size));
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003879 data->EndOfFile = data->AllocationSize;
3880 data->Attributes =
Steve French70ca7342005-09-22 16:32:06 -07003881 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003882 } else
3883 rc = -EIO; /* bad buffer passed in */
3884
3885 cifs_buf_release(pSMB);
3886
3887 if (rc == -EAGAIN)
3888 goto QInfRetry;
3889
3890 return rc;
3891}
3892
Jeff Laytonbcd53572010-02-12 07:44:16 -05003893int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003894CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonbcd53572010-02-12 07:44:16 -05003895 u16 netfid, FILE_ALL_INFO *pFindData)
3896{
3897 struct smb_t2_qfi_req *pSMB = NULL;
3898 struct smb_t2_qfi_rsp *pSMBr = NULL;
3899 int rc = 0;
3900 int bytes_returned;
3901 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07003902
Jeff Laytonbcd53572010-02-12 07:44:16 -05003903QFileInfoRetry:
3904 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3905 (void **) &pSMBr);
3906 if (rc)
3907 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07003908
Jeff Laytonbcd53572010-02-12 07:44:16 -05003909 params = 2 /* level */ + 2 /* fid */;
3910 pSMB->t2.TotalDataCount = 0;
3911 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3912 /* BB find exact max data count below from sess structure BB */
3913 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3914 pSMB->t2.MaxSetupCount = 0;
3915 pSMB->t2.Reserved = 0;
3916 pSMB->t2.Flags = 0;
3917 pSMB->t2.Timeout = 0;
3918 pSMB->t2.Reserved2 = 0;
3919 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3920 Fid) - 4);
3921 pSMB->t2.DataCount = 0;
3922 pSMB->t2.DataOffset = 0;
3923 pSMB->t2.SetupCount = 1;
3924 pSMB->t2.Reserved3 = 0;
3925 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3926 byte_count = params + 1 /* pad */ ;
3927 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3928 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3929 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3930 pSMB->Pad = 0;
3931 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003932 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003933
3934 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3935 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3936 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00003937 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003938 } else { /* decode response */
3939 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3940
3941 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3942 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04003943 else if (get_bcc(&pSMBr->hdr) < 40)
Jeff Laytonbcd53572010-02-12 07:44:16 -05003944 rc = -EIO; /* bad smb */
3945 else if (pFindData) {
3946 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3947 memcpy((char *) pFindData,
3948 (char *) &pSMBr->hdr.Protocol +
3949 data_offset, sizeof(FILE_ALL_INFO));
3950 } else
3951 rc = -ENOMEM;
3952 }
3953 cifs_buf_release(pSMB);
3954 if (rc == -EAGAIN)
3955 goto QFileInfoRetry;
3956
3957 return rc;
3958}
Steve French6b8edfe2005-08-23 20:26:03 -07003959
Linus Torvalds1da177e2005-04-16 15:20:36 -07003960int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003961CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003962 const char *search_name, FILE_ALL_INFO *data,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003963 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003964 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003965{
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003966 /* level 263 SMB_QUERY_FILE_ALL_INFO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003967 TRANSACTION2_QPI_REQ *pSMB = NULL;
3968 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3969 int rc = 0;
3970 int bytes_returned;
3971 int name_len;
3972 __u16 params, byte_count;
3973
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003974 /* cFYI(1, "In QPathInfo path %s", search_name); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003975QPathInfoRetry:
3976 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3977 (void **) &pSMBr);
3978 if (rc)
3979 return rc;
3980
3981 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3982 name_len =
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003983 cifsConvertToUTF16((__le16 *) pSMB->FileName, search_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06003984 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003985 name_len++; /* trailing null */
3986 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003987 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003988 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003989 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003990 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003991 }
3992
Steve French50c2f752007-07-13 00:33:32 +00003993 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003994 pSMB->TotalDataCount = 0;
3995 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003996 /* BB find exact max SMB PDU from sess structure BB */
3997 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003998 pSMB->MaxSetupCount = 0;
3999 pSMB->Reserved = 0;
4000 pSMB->Flags = 0;
4001 pSMB->Timeout = 0;
4002 pSMB->Reserved2 = 0;
4003 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004004 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004005 pSMB->DataCount = 0;
4006 pSMB->DataOffset = 0;
4007 pSMB->SetupCount = 1;
4008 pSMB->Reserved3 = 0;
4009 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4010 byte_count = params + 1 /* pad */ ;
4011 pSMB->TotalParameterCount = cpu_to_le16(params);
4012 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00004013 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004014 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
4015 else
4016 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004017 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004018 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004019 pSMB->ByteCount = cpu_to_le16(byte_count);
4020
4021 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4022 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4023 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004024 cFYI(1, "Send error in QPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004025 } else { /* decode response */
4026 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4027
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004028 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4029 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004030 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004031 rc = -EIO; /* bad smb */
Jeff Layton820a8032011-05-04 08:05:26 -04004032 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
Steve French50c2f752007-07-13 00:33:32 +00004033 rc = -EIO; /* 24 or 26 expected but we do not read
4034 last field */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004035 else if (data) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004036 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004037 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00004038
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004039 /*
4040 * On legacy responses we do not read the last field,
4041 * EAsize, fortunately since it varies by subdialect and
4042 * also note it differs on Set vs Get, ie two bytes or 4
4043 * bytes depending but we don't care here.
4044 */
Steve Frenchad7a2922008-02-07 23:25:02 +00004045 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004046 size = sizeof(FILE_INFO_STANDARD);
4047 else
4048 size = sizeof(FILE_ALL_INFO);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004049 memcpy((char *) data, (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004050 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004051 } else
4052 rc = -ENOMEM;
4053 }
4054 cifs_buf_release(pSMB);
4055 if (rc == -EAGAIN)
4056 goto QPathInfoRetry;
4057
4058 return rc;
4059}
4060
4061int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004062CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004063 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
4064{
4065 struct smb_t2_qfi_req *pSMB = NULL;
4066 struct smb_t2_qfi_rsp *pSMBr = NULL;
4067 int rc = 0;
4068 int bytes_returned;
4069 __u16 params, byte_count;
4070
4071UnixQFileInfoRetry:
4072 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4073 (void **) &pSMBr);
4074 if (rc)
4075 return rc;
4076
4077 params = 2 /* level */ + 2 /* fid */;
4078 pSMB->t2.TotalDataCount = 0;
4079 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4080 /* BB find exact max data count below from sess structure BB */
4081 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4082 pSMB->t2.MaxSetupCount = 0;
4083 pSMB->t2.Reserved = 0;
4084 pSMB->t2.Flags = 0;
4085 pSMB->t2.Timeout = 0;
4086 pSMB->t2.Reserved2 = 0;
4087 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4088 Fid) - 4);
4089 pSMB->t2.DataCount = 0;
4090 pSMB->t2.DataOffset = 0;
4091 pSMB->t2.SetupCount = 1;
4092 pSMB->t2.Reserved3 = 0;
4093 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4094 byte_count = params + 1 /* pad */ ;
4095 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4096 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4097 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4098 pSMB->Pad = 0;
4099 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004100 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004101
4102 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4103 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4104 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00004105 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004106 } else { /* decode response */
4107 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4108
Jeff Layton820a8032011-05-04 08:05:26 -04004109 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004110 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response. "
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004111 "Unix Extensions can be disabled on mount "
Steve Frenchf19159d2010-04-21 04:12:10 +00004112 "by specifying the nosfu mount option.");
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004113 rc = -EIO; /* bad smb */
4114 } else {
4115 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4116 memcpy((char *) pFindData,
4117 (char *) &pSMBr->hdr.Protocol +
4118 data_offset,
4119 sizeof(FILE_UNIX_BASIC_INFO));
4120 }
4121 }
4122
4123 cifs_buf_release(pSMB);
4124 if (rc == -EAGAIN)
4125 goto UnixQFileInfoRetry;
4126
4127 return rc;
4128}
4129
4130int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004131CIFSSMBUnixQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004132 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00004133 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07004134 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004135{
4136/* SMB_QUERY_FILE_UNIX_BASIC */
4137 TRANSACTION2_QPI_REQ *pSMB = NULL;
4138 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4139 int rc = 0;
4140 int bytes_returned = 0;
4141 int name_len;
4142 __u16 params, byte_count;
4143
Joe Perchesb6b38f72010-04-21 03:50:45 +00004144 cFYI(1, "In QPathInfo (Unix) the path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004145UnixQPathInfoRetry:
4146 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4147 (void **) &pSMBr);
4148 if (rc)
4149 return rc;
4150
4151 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4152 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004153 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4154 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004155 name_len++; /* trailing null */
4156 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004157 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004158 name_len = strnlen(searchName, PATH_MAX);
4159 name_len++; /* trailing null */
4160 strncpy(pSMB->FileName, searchName, name_len);
4161 }
4162
Steve French50c2f752007-07-13 00:33:32 +00004163 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004164 pSMB->TotalDataCount = 0;
4165 pSMB->MaxParameterCount = cpu_to_le16(2);
4166 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00004167 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004168 pSMB->MaxSetupCount = 0;
4169 pSMB->Reserved = 0;
4170 pSMB->Flags = 0;
4171 pSMB->Timeout = 0;
4172 pSMB->Reserved2 = 0;
4173 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004174 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004175 pSMB->DataCount = 0;
4176 pSMB->DataOffset = 0;
4177 pSMB->SetupCount = 1;
4178 pSMB->Reserved3 = 0;
4179 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4180 byte_count = params + 1 /* pad */ ;
4181 pSMB->TotalParameterCount = cpu_to_le16(params);
4182 pSMB->ParameterCount = pSMB->TotalParameterCount;
4183 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4184 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004185 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004186 pSMB->ByteCount = cpu_to_le16(byte_count);
4187
4188 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4189 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4190 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004191 cFYI(1, "Send error in QPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004192 } else { /* decode response */
4193 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4194
Jeff Layton820a8032011-05-04 08:05:26 -04004195 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004196 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response. "
Steve French1e71f252007-09-20 15:30:07 +00004197 "Unix Extensions can be disabled on mount "
Joe Perchesb6b38f72010-04-21 03:50:45 +00004198 "by specifying the nosfu mount option.");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004199 rc = -EIO; /* bad smb */
4200 } else {
4201 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4202 memcpy((char *) pFindData,
4203 (char *) &pSMBr->hdr.Protocol +
4204 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00004205 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004206 }
4207 }
4208 cifs_buf_release(pSMB);
4209 if (rc == -EAGAIN)
4210 goto UnixQPathInfoRetry;
4211
4212 return rc;
4213}
4214
Linus Torvalds1da177e2005-04-16 15:20:36 -07004215/* xid, tcon, searchName and codepage are input parms, rest are returned */
4216int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004217CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004218 const char *searchName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004219 const struct nls_table *nls_codepage,
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004220 __u16 *pnetfid, __u16 search_flags,
Steve French50c2f752007-07-13 00:33:32 +00004221 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004222{
4223/* level 257 SMB_ */
4224 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
4225 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004226 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004227 int rc = 0;
4228 int bytes_returned = 0;
4229 int name_len;
4230 __u16 params, byte_count;
4231
Joe Perchesb6b38f72010-04-21 03:50:45 +00004232 cFYI(1, "In FindFirst for %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004233
4234findFirstRetry:
4235 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4236 (void **) &pSMBr);
4237 if (rc)
4238 return rc;
4239
4240 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4241 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004242 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4243 PATH_MAX, nls_codepage, remap);
Steve French737b7582005-04-28 22:41:06 -07004244 /* We can not add the asterik earlier in case
4245 it got remapped to 0xF03A as if it were part of the
4246 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004247 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07004248 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07004249 pSMB->FileName[name_len+1] = 0;
4250 pSMB->FileName[name_len+2] = '*';
4251 pSMB->FileName[name_len+3] = 0;
4252 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004253 pSMB->FileName[name_len] = 0; /* null terminate just in case */
4254 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07004255 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004256 } else { /* BB add check for overrun of SMB buf BB */
4257 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004258/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00004259 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004260 free buffer exit; BB */
4261 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07004262 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07004263 pSMB->FileName[name_len+1] = '*';
4264 pSMB->FileName[name_len+2] = 0;
4265 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004266 }
4267
4268 params = 12 + name_len /* includes null */ ;
4269 pSMB->TotalDataCount = 0; /* no EAs */
4270 pSMB->MaxParameterCount = cpu_to_le16(10);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004271 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004272 pSMB->MaxSetupCount = 0;
4273 pSMB->Reserved = 0;
4274 pSMB->Flags = 0;
4275 pSMB->Timeout = 0;
4276 pSMB->Reserved2 = 0;
4277 byte_count = params + 1 /* pad */ ;
4278 pSMB->TotalParameterCount = cpu_to_le16(params);
4279 pSMB->ParameterCount = pSMB->TotalParameterCount;
4280 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00004281 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
4282 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004283 pSMB->DataCount = 0;
4284 pSMB->DataOffset = 0;
4285 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
4286 pSMB->Reserved3 = 0;
4287 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
4288 pSMB->SearchAttributes =
4289 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
4290 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00004291 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004292 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004293 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4294
4295 /* BB what should we set StorageType to? Does it matter? BB */
4296 pSMB->SearchStorageType = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004297 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004298 pSMB->ByteCount = cpu_to_le16(byte_count);
4299
4300 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4301 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004302 cifs_stats_inc(&tcon->stats.cifs_stats.num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004303
Steve French88274812006-03-09 22:21:45 +00004304 if (rc) {/* BB add logic to retry regular search if Unix search
4305 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004306 /* BB Add code to handle unsupported level rc */
Joe Perchesb6b38f72010-04-21 03:50:45 +00004307 cFYI(1, "Error in FindFirst = %d", rc);
Steve French1982c342005-08-17 12:38:22 -07004308
Steve French88274812006-03-09 22:21:45 +00004309 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004310
4311 /* BB eventually could optimize out free and realloc of buf */
4312 /* for this case */
4313 if (rc == -EAGAIN)
4314 goto findFirstRetry;
4315 } else { /* decode response */
4316 /* BB remember to free buffer if error BB */
4317 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00004318 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004319 unsigned int lnoff;
4320
Linus Torvalds1da177e2005-04-16 15:20:36 -07004321 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004322 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004323 else
Steve French4b18f2a2008-04-29 00:06:05 +00004324 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004325
4326 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004327 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00004328 psrch_inf->srch_entries_start =
4329 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004330 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004331 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
4332 le16_to_cpu(pSMBr->t2.ParameterOffset));
4333
Steve French790fe572007-07-07 19:25:05 +00004334 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004335 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004336 else
Steve French4b18f2a2008-04-29 00:06:05 +00004337 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004338
Steve French50c2f752007-07-13 00:33:32 +00004339 psrch_inf->entries_in_buffer =
4340 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00004341 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004342 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004343 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004344 if (CIFSMaxBufSize < lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004345 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00004346 psrch_inf->last_entry = NULL;
4347 return rc;
4348 }
4349
Steve French0752f152008-10-07 20:03:33 +00004350 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00004351 lnoff;
4352
Linus Torvalds1da177e2005-04-16 15:20:36 -07004353 *pnetfid = parms->SearchHandle;
4354 } else {
4355 cifs_buf_release(pSMB);
4356 }
4357 }
4358
4359 return rc;
4360}
4361
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004362int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
4363 __u16 searchHandle, __u16 search_flags,
4364 struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004365{
4366 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
4367 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004368 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004369 char *response_data;
4370 int rc = 0;
Jeff Layton9438fab2011-08-23 07:21:28 -04004371 int bytes_returned;
4372 unsigned int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004373 __u16 params, byte_count;
4374
Joe Perchesb6b38f72010-04-21 03:50:45 +00004375 cFYI(1, "In FindNext");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004376
Steve French4b18f2a2008-04-29 00:06:05 +00004377 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004378 return -ENOENT;
4379
4380 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4381 (void **) &pSMBr);
4382 if (rc)
4383 return rc;
4384
Steve French50c2f752007-07-13 00:33:32 +00004385 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004386 byte_count = 0;
4387 pSMB->TotalDataCount = 0; /* no EAs */
4388 pSMB->MaxParameterCount = cpu_to_le16(8);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004389 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004390 pSMB->MaxSetupCount = 0;
4391 pSMB->Reserved = 0;
4392 pSMB->Flags = 0;
4393 pSMB->Timeout = 0;
4394 pSMB->Reserved2 = 0;
4395 pSMB->ParameterOffset = cpu_to_le16(
4396 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
4397 pSMB->DataCount = 0;
4398 pSMB->DataOffset = 0;
4399 pSMB->SetupCount = 1;
4400 pSMB->Reserved3 = 0;
4401 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
4402 pSMB->SearchHandle = searchHandle; /* always kept as le */
4403 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00004404 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004405 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4406 pSMB->ResumeKey = psrch_inf->resume_key;
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004407 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004408
4409 name_len = psrch_inf->resume_name_len;
4410 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00004411 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004412 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
4413 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07004414 /* 14 byte parm len above enough for 2 byte null terminator */
4415 pSMB->ResumeFileName[name_len] = 0;
4416 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004417 } else {
4418 rc = -EINVAL;
4419 goto FNext2_err_exit;
4420 }
4421 byte_count = params + 1 /* pad */ ;
4422 pSMB->TotalParameterCount = cpu_to_le16(params);
4423 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004424 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004425 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004426
Linus Torvalds1da177e2005-04-16 15:20:36 -07004427 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4428 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004429 cifs_stats_inc(&tcon->stats.cifs_stats.num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004430 if (rc) {
4431 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00004432 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07004433 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00004434 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004435 } else
Joe Perchesb6b38f72010-04-21 03:50:45 +00004436 cFYI(1, "FindNext returned = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004437 } else { /* decode response */
4438 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00004439
Steve French790fe572007-07-07 19:25:05 +00004440 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004441 unsigned int lnoff;
4442
Linus Torvalds1da177e2005-04-16 15:20:36 -07004443 /* BB fixme add lock for file (srch_info) struct here */
4444 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004445 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004446 else
Steve French4b18f2a2008-04-29 00:06:05 +00004447 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004448 response_data = (char *) &pSMBr->hdr.Protocol +
4449 le16_to_cpu(pSMBr->t2.ParameterOffset);
4450 parms = (T2_FNEXT_RSP_PARMS *)response_data;
4451 response_data = (char *)&pSMBr->hdr.Protocol +
4452 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00004453 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00004454 cifs_small_buf_release(
4455 psrch_inf->ntwrk_buf_start);
4456 else
4457 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004458 psrch_inf->srch_entries_start = response_data;
4459 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004460 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00004461 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004462 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004463 else
Steve French4b18f2a2008-04-29 00:06:05 +00004464 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00004465 psrch_inf->entries_in_buffer =
4466 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004467 psrch_inf->index_of_last_entry +=
4468 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004469 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004470 if (CIFSMaxBufSize < lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004471 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00004472 psrch_inf->last_entry = NULL;
4473 return rc;
4474 } else
4475 psrch_inf->last_entry =
4476 psrch_inf->srch_entries_start + lnoff;
4477
Joe Perchesb6b38f72010-04-21 03:50:45 +00004478/* cFYI(1, "fnxt2 entries in buf %d index_of_last %d",
4479 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004480
4481 /* BB fixme add unlock here */
4482 }
4483
4484 }
4485
4486 /* BB On error, should we leave previous search buf (and count and
4487 last entry fields) intact or free the previous one? */
4488
4489 /* Note: On -EAGAIN error only caller can retry on handle based calls
4490 since file handle passed in no longer valid */
4491FNext2_err_exit:
4492 if (rc != 0)
4493 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004494 return rc;
4495}
4496
4497int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004498CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004499 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004500{
4501 int rc = 0;
4502 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004503
Joe Perchesb6b38f72010-04-21 03:50:45 +00004504 cFYI(1, "In CIFSSMBFindClose");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004505 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
4506
4507 /* no sense returning error if session restarted
4508 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00004509 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004510 return 0;
4511 if (rc)
4512 return rc;
4513
Linus Torvalds1da177e2005-04-16 15:20:36 -07004514 pSMB->FileID = searchHandle;
4515 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04004516 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004517 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00004518 cERROR(1, "Send error in FindClose = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00004519
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004520 cifs_stats_inc(&tcon->stats.cifs_stats.num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004521
4522 /* Since session is dead, search handle closed on server already */
4523 if (rc == -EAGAIN)
4524 rc = 0;
4525
4526 return rc;
4527}
4528
Linus Torvalds1da177e2005-04-16 15:20:36 -07004529int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004530CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004531 const char *search_name, __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00004532 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004533{
4534 int rc = 0;
4535 TRANSACTION2_QPI_REQ *pSMB = NULL;
4536 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4537 int name_len, bytes_returned;
4538 __u16 params, byte_count;
4539
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004540 cFYI(1, "In GetSrvInodeNum for %s", search_name);
Steve French790fe572007-07-07 19:25:05 +00004541 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00004542 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004543
4544GetInodeNumberRetry:
4545 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004546 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004547 if (rc)
4548 return rc;
4549
Linus Torvalds1da177e2005-04-16 15:20:36 -07004550 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4551 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004552 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004553 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004554 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004555 name_len++; /* trailing null */
4556 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004557 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004558 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004559 name_len++; /* trailing null */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004560 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004561 }
4562
4563 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4564 pSMB->TotalDataCount = 0;
4565 pSMB->MaxParameterCount = cpu_to_le16(2);
4566 /* BB find exact max data count below from sess structure BB */
4567 pSMB->MaxDataCount = cpu_to_le16(4000);
4568 pSMB->MaxSetupCount = 0;
4569 pSMB->Reserved = 0;
4570 pSMB->Flags = 0;
4571 pSMB->Timeout = 0;
4572 pSMB->Reserved2 = 0;
4573 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004574 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004575 pSMB->DataCount = 0;
4576 pSMB->DataOffset = 0;
4577 pSMB->SetupCount = 1;
4578 pSMB->Reserved3 = 0;
4579 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4580 byte_count = params + 1 /* pad */ ;
4581 pSMB->TotalParameterCount = cpu_to_le16(params);
4582 pSMB->ParameterCount = pSMB->TotalParameterCount;
4583 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4584 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004585 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004586 pSMB->ByteCount = cpu_to_le16(byte_count);
4587
4588 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4589 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4590 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004591 cFYI(1, "error %d in QueryInternalInfo", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004592 } else {
4593 /* decode response */
4594 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004595 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04004596 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004597 /* If rc should we check for EOPNOSUPP and
4598 disable the srvino flag? or in caller? */
4599 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00004600 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004601 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4602 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00004603 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004604 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00004605 if (count < 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004606 cFYI(1, "Illegal size ret in QryIntrnlInf");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004607 rc = -EIO;
4608 goto GetInodeNumOut;
4609 }
4610 pfinfo = (struct file_internal_info *)
4611 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00004612 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004613 }
4614 }
4615GetInodeNumOut:
4616 cifs_buf_release(pSMB);
4617 if (rc == -EAGAIN)
4618 goto GetInodeNumberRetry;
4619 return rc;
4620}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004621
Igor Mammedovfec45852008-05-16 13:06:30 +04004622/* parses DFS refferal V3 structure
4623 * caller is responsible for freeing target_nodes
4624 * returns:
4625 * on success - 0
4626 * on failure - errno
4627 */
4628static int
Steve Frencha1fe78f2008-05-16 18:48:38 +00004629parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
Igor Mammedovfec45852008-05-16 13:06:30 +04004630 unsigned int *num_of_nodes,
4631 struct dfs_info3_param **target_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004632 const struct nls_table *nls_codepage, int remap,
4633 const char *searchName)
Igor Mammedovfec45852008-05-16 13:06:30 +04004634{
4635 int i, rc = 0;
4636 char *data_end;
4637 bool is_unicode;
4638 struct dfs_referral_level_3 *ref;
4639
Harvey Harrison5ca33c62008-07-23 17:45:58 -07004640 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4641 is_unicode = true;
4642 else
4643 is_unicode = false;
Igor Mammedovfec45852008-05-16 13:06:30 +04004644 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
4645
4646 if (*num_of_nodes < 1) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004647 cERROR(1, "num_referrals: must be at least > 0,"
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004648 "but we get num_referrals = %d", *num_of_nodes);
Igor Mammedovfec45852008-05-16 13:06:30 +04004649 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004650 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004651 }
4652
4653 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
Al Viro1d92cfd2008-06-02 10:59:02 +01004654 if (ref->VersionNumber != cpu_to_le16(3)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004655 cERROR(1, "Referrals of V%d version are not supported,"
4656 "should be V3", le16_to_cpu(ref->VersionNumber));
Igor Mammedovfec45852008-05-16 13:06:30 +04004657 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004658 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004659 }
4660
4661 /* get the upper boundary of the resp buffer */
4662 data_end = (char *)(&(pSMBr->PathConsumed)) +
4663 le16_to_cpu(pSMBr->t2.DataCount);
4664
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004665 cFYI(1, "num_referrals: %d dfs flags: 0x%x ...",
Igor Mammedovfec45852008-05-16 13:06:30 +04004666 *num_of_nodes,
Joe Perchesb6b38f72010-04-21 03:50:45 +00004667 le32_to_cpu(pSMBr->DFSFlags));
Igor Mammedovfec45852008-05-16 13:06:30 +04004668
4669 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
4670 *num_of_nodes, GFP_KERNEL);
4671 if (*target_nodes == NULL) {
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004672 cERROR(1, "Failed to allocate buffer for target_nodes");
Igor Mammedovfec45852008-05-16 13:06:30 +04004673 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004674 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004675 }
4676
Daniel Mack3ad2f3f2010-02-03 08:01:28 +08004677 /* collect necessary data from referrals */
Igor Mammedovfec45852008-05-16 13:06:30 +04004678 for (i = 0; i < *num_of_nodes; i++) {
4679 char *temp;
4680 int max_len;
4681 struct dfs_info3_param *node = (*target_nodes)+i;
4682
Steve French0e0d2cf2009-05-01 05:27:32 +00004683 node->flags = le32_to_cpu(pSMBr->DFSFlags);
Igor Mammedov2c556082008-10-23 13:58:42 +04004684 if (is_unicode) {
Jeff Layton331c3132008-12-17 06:31:53 -05004685 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4686 GFP_KERNEL);
Steve French2920ee22009-08-31 15:27:26 +00004687 if (tmp == NULL) {
4688 rc = -ENOMEM;
4689 goto parse_DFS_referrals_exit;
4690 }
Steve Frenchacbbb762012-01-18 22:32:33 -06004691 cifsConvertToUTF16((__le16 *) tmp, searchName,
4692 PATH_MAX, nls_codepage, remap);
4693 node->path_consumed = cifs_utf16_bytes(tmp,
Jeff Layton69f801f2009-04-30 06:46:32 -04004694 le16_to_cpu(pSMBr->PathConsumed),
Igor Mammedov2c556082008-10-23 13:58:42 +04004695 nls_codepage);
4696 kfree(tmp);
4697 } else
4698 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4699
Igor Mammedovfec45852008-05-16 13:06:30 +04004700 node->server_type = le16_to_cpu(ref->ServerType);
4701 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4702
4703 /* copy DfsPath */
4704 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4705 max_len = data_end - temp;
Steve Frenchacbbb762012-01-18 22:32:33 -06004706 node->path_name = cifs_strndup_from_utf16(temp, max_len,
4707 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004708 if (!node->path_name) {
4709 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004710 goto parse_DFS_referrals_exit;
Jeff Layton066ce682009-04-30 07:16:14 -04004711 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004712
4713 /* copy link target UNC */
4714 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4715 max_len = data_end - temp;
Steve Frenchacbbb762012-01-18 22:32:33 -06004716 node->node_name = cifs_strndup_from_utf16(temp, max_len,
4717 is_unicode, nls_codepage);
Stefan Metzmacherd8f27992012-05-04 00:19:28 +02004718 if (!node->node_name) {
Jeff Laytond8e2f532009-05-14 07:46:59 -04004719 rc = -ENOMEM;
Stefan Metzmacherd8f27992012-05-04 00:19:28 +02004720 goto parse_DFS_referrals_exit;
4721 }
4722
4723 ref++;
Igor Mammedovfec45852008-05-16 13:06:30 +04004724 }
4725
Steve Frencha1fe78f2008-05-16 18:48:38 +00004726parse_DFS_referrals_exit:
Igor Mammedovfec45852008-05-16 13:06:30 +04004727 if (rc) {
4728 free_dfs_info_array(*target_nodes, *num_of_nodes);
4729 *target_nodes = NULL;
4730 *num_of_nodes = 0;
4731 }
4732 return rc;
4733}
4734
Linus Torvalds1da177e2005-04-16 15:20:36 -07004735int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004736CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004737 const char *search_name, struct dfs_info3_param **target_nodes,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004738 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004739 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004740{
4741/* TRANS2_GET_DFS_REFERRAL */
4742 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4743 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004744 int rc = 0;
4745 int bytes_returned;
4746 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004747 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004748 *num_of_nodes = 0;
4749 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004750
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004751 cFYI(1, "In GetDFSRefer the path %s", search_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004752 if (ses == NULL)
4753 return -ENODEV;
4754getDFSRetry:
4755 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4756 (void **) &pSMBr);
4757 if (rc)
4758 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004759
4760 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004761 but should never be null here anyway */
Pavel Shilovsky88257362012-05-23 14:01:59 +04004762 pSMB->hdr.Mid = get_next_mid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004763 pSMB->hdr.Tid = ses->ipc_tid;
4764 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004765 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004766 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004767 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004768 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004769
4770 if (ses->capabilities & CAP_UNICODE) {
4771 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4772 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004773 cifsConvertToUTF16((__le16 *) pSMB->RequestFileName,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004774 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004775 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004776 name_len++; /* trailing null */
4777 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004778 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004779 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004780 name_len++; /* trailing null */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004781 strncpy(pSMB->RequestFileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004782 }
4783
Steve French790fe572007-07-07 19:25:05 +00004784 if (ses->server) {
Steve French96daf2b2011-05-27 04:34:02 +00004785 if (ses->server->sec_mode &
Steve French1a4e15a2006-10-12 21:33:51 +00004786 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4787 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4788 }
4789
Steve French50c2f752007-07-13 00:33:32 +00004790 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004791
Linus Torvalds1da177e2005-04-16 15:20:36 -07004792 params = 2 /* level */ + name_len /*includes null */ ;
4793 pSMB->TotalDataCount = 0;
4794 pSMB->DataCount = 0;
4795 pSMB->DataOffset = 0;
4796 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004797 /* BB find exact max SMB PDU from sess structure BB */
4798 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004799 pSMB->MaxSetupCount = 0;
4800 pSMB->Reserved = 0;
4801 pSMB->Flags = 0;
4802 pSMB->Timeout = 0;
4803 pSMB->Reserved2 = 0;
4804 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004805 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004806 pSMB->SetupCount = 1;
4807 pSMB->Reserved3 = 0;
4808 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4809 byte_count = params + 3 /* pad */ ;
4810 pSMB->ParameterCount = cpu_to_le16(params);
4811 pSMB->TotalParameterCount = pSMB->ParameterCount;
4812 pSMB->MaxReferralLevel = cpu_to_le16(3);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004813 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004814 pSMB->ByteCount = cpu_to_le16(byte_count);
4815
4816 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4817 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4818 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004819 cFYI(1, "Send error in GetDFSRefer = %d", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004820 goto GetDFSRefExit;
4821 }
4822 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004823
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004824 /* BB Also check if enough total bytes returned? */
Jeff Layton820a8032011-05-04 08:05:26 -04004825 if (rc || get_bcc(&pSMBr->hdr) < 17) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004826 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004827 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004828 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004829
Joe Perchesb6b38f72010-04-21 03:50:45 +00004830 cFYI(1, "Decoding GetDFSRefer response BCC: %d Offset %d",
Jeff Layton820a8032011-05-04 08:05:26 -04004831 get_bcc(&pSMBr->hdr),
Joe Perchesb6b38f72010-04-21 03:50:45 +00004832 le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04004833
4834 /* parse returned result into more usable form */
Steve Frencha1fe78f2008-05-16 18:48:38 +00004835 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004836 target_nodes, nls_codepage, remap,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004837 search_name);
Igor Mammedovfec45852008-05-16 13:06:30 +04004838
Linus Torvalds1da177e2005-04-16 15:20:36 -07004839GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004840 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004841
4842 if (rc == -EAGAIN)
4843 goto getDFSRetry;
4844
4845 return rc;
4846}
4847
Steve French20962432005-09-21 22:05:57 -07004848/* Query File System Info such as free space to old servers such as Win 9x */
4849int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004850SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4851 struct kstatfs *FSData)
Steve French20962432005-09-21 22:05:57 -07004852{
4853/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4854 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4855 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4856 FILE_SYSTEM_ALLOC_INFO *response_data;
4857 int rc = 0;
4858 int bytes_returned = 0;
4859 __u16 params, byte_count;
4860
Joe Perchesb6b38f72010-04-21 03:50:45 +00004861 cFYI(1, "OldQFSInfo");
Steve French20962432005-09-21 22:05:57 -07004862oldQFSInfoRetry:
4863 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4864 (void **) &pSMBr);
4865 if (rc)
4866 return rc;
Steve French20962432005-09-21 22:05:57 -07004867
4868 params = 2; /* level */
4869 pSMB->TotalDataCount = 0;
4870 pSMB->MaxParameterCount = cpu_to_le16(2);
4871 pSMB->MaxDataCount = cpu_to_le16(1000);
4872 pSMB->MaxSetupCount = 0;
4873 pSMB->Reserved = 0;
4874 pSMB->Flags = 0;
4875 pSMB->Timeout = 0;
4876 pSMB->Reserved2 = 0;
4877 byte_count = params + 1 /* pad */ ;
4878 pSMB->TotalParameterCount = cpu_to_le16(params);
4879 pSMB->ParameterCount = pSMB->TotalParameterCount;
4880 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4881 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4882 pSMB->DataCount = 0;
4883 pSMB->DataOffset = 0;
4884 pSMB->SetupCount = 1;
4885 pSMB->Reserved3 = 0;
4886 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4887 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004888 inc_rfc1001_len(pSMB, byte_count);
Steve French20962432005-09-21 22:05:57 -07004889 pSMB->ByteCount = cpu_to_le16(byte_count);
4890
4891 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4892 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4893 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004894 cFYI(1, "Send error in QFSInfo = %d", rc);
Steve French20962432005-09-21 22:05:57 -07004895 } else { /* decode response */
4896 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4897
Jeff Layton820a8032011-05-04 08:05:26 -04004898 if (rc || get_bcc(&pSMBr->hdr) < 18)
Steve French20962432005-09-21 22:05:57 -07004899 rc = -EIO; /* bad smb */
4900 else {
4901 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004902 cFYI(1, "qfsinf resp BCC: %d Offset %d",
Jeff Layton820a8032011-05-04 08:05:26 -04004903 get_bcc(&pSMBr->hdr), data_offset);
Steve French20962432005-09-21 22:05:57 -07004904
Steve French50c2f752007-07-13 00:33:32 +00004905 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004906 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4907 FSData->f_bsize =
4908 le16_to_cpu(response_data->BytesPerSector) *
4909 le32_to_cpu(response_data->
4910 SectorsPerAllocationUnit);
4911 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004912 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004913 FSData->f_bfree = FSData->f_bavail =
4914 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004915 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
4916 (unsigned long long)FSData->f_blocks,
4917 (unsigned long long)FSData->f_bfree,
4918 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07004919 }
4920 }
4921 cifs_buf_release(pSMB);
4922
4923 if (rc == -EAGAIN)
4924 goto oldQFSInfoRetry;
4925
4926 return rc;
4927}
4928
Linus Torvalds1da177e2005-04-16 15:20:36 -07004929int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004930CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4931 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004932{
4933/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4934 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4935 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4936 FILE_SYSTEM_INFO *response_data;
4937 int rc = 0;
4938 int bytes_returned = 0;
4939 __u16 params, byte_count;
4940
Joe Perchesb6b38f72010-04-21 03:50:45 +00004941 cFYI(1, "In QFSInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004942QFSInfoRetry:
4943 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4944 (void **) &pSMBr);
4945 if (rc)
4946 return rc;
4947
4948 params = 2; /* level */
4949 pSMB->TotalDataCount = 0;
4950 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004951 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004952 pSMB->MaxSetupCount = 0;
4953 pSMB->Reserved = 0;
4954 pSMB->Flags = 0;
4955 pSMB->Timeout = 0;
4956 pSMB->Reserved2 = 0;
4957 byte_count = params + 1 /* pad */ ;
4958 pSMB->TotalParameterCount = cpu_to_le16(params);
4959 pSMB->ParameterCount = pSMB->TotalParameterCount;
4960 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004961 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004962 pSMB->DataCount = 0;
4963 pSMB->DataOffset = 0;
4964 pSMB->SetupCount = 1;
4965 pSMB->Reserved3 = 0;
4966 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4967 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004968 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004969 pSMB->ByteCount = cpu_to_le16(byte_count);
4970
4971 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4972 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4973 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004974 cFYI(1, "Send error in QFSInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004975 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00004976 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004977
Jeff Layton820a8032011-05-04 08:05:26 -04004978 if (rc || get_bcc(&pSMBr->hdr) < 24)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004979 rc = -EIO; /* bad smb */
4980 else {
4981 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004982
4983 response_data =
4984 (FILE_SYSTEM_INFO
4985 *) (((char *) &pSMBr->hdr.Protocol) +
4986 data_offset);
4987 FSData->f_bsize =
4988 le32_to_cpu(response_data->BytesPerSector) *
4989 le32_to_cpu(response_data->
4990 SectorsPerAllocationUnit);
4991 FSData->f_blocks =
4992 le64_to_cpu(response_data->TotalAllocationUnits);
4993 FSData->f_bfree = FSData->f_bavail =
4994 le64_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004995 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
4996 (unsigned long long)FSData->f_blocks,
4997 (unsigned long long)FSData->f_bfree,
4998 FSData->f_bsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004999 }
5000 }
5001 cifs_buf_release(pSMB);
5002
5003 if (rc == -EAGAIN)
5004 goto QFSInfoRetry;
5005
5006 return rc;
5007}
5008
5009int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005010CIFSSMBQFSAttributeInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005011{
5012/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
5013 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5014 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5015 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
5016 int rc = 0;
5017 int bytes_returned = 0;
5018 __u16 params, byte_count;
5019
Joe Perchesb6b38f72010-04-21 03:50:45 +00005020 cFYI(1, "In QFSAttributeInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005021QFSAttributeRetry:
5022 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5023 (void **) &pSMBr);
5024 if (rc)
5025 return rc;
5026
5027 params = 2; /* level */
5028 pSMB->TotalDataCount = 0;
5029 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005030 /* BB find exact max SMB PDU from sess structure BB */
5031 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005032 pSMB->MaxSetupCount = 0;
5033 pSMB->Reserved = 0;
5034 pSMB->Flags = 0;
5035 pSMB->Timeout = 0;
5036 pSMB->Reserved2 = 0;
5037 byte_count = params + 1 /* pad */ ;
5038 pSMB->TotalParameterCount = cpu_to_le16(params);
5039 pSMB->ParameterCount = pSMB->TotalParameterCount;
5040 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005041 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005042 pSMB->DataCount = 0;
5043 pSMB->DataOffset = 0;
5044 pSMB->SetupCount = 1;
5045 pSMB->Reserved3 = 0;
5046 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5047 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005048 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005049 pSMB->ByteCount = cpu_to_le16(byte_count);
5050
5051 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5052 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5053 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005054 cERROR(1, "Send error in QFSAttributeInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005055 } else { /* decode response */
5056 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5057
Jeff Layton820a8032011-05-04 08:05:26 -04005058 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Steve French50c2f752007-07-13 00:33:32 +00005059 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005060 rc = -EIO; /* bad smb */
5061 } else {
5062 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5063 response_data =
5064 (FILE_SYSTEM_ATTRIBUTE_INFO
5065 *) (((char *) &pSMBr->hdr.Protocol) +
5066 data_offset);
5067 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005068 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005069 }
5070 }
5071 cifs_buf_release(pSMB);
5072
5073 if (rc == -EAGAIN)
5074 goto QFSAttributeRetry;
5075
5076 return rc;
5077}
5078
5079int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005080CIFSSMBQFSDeviceInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005081{
5082/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
5083 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5084 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5085 FILE_SYSTEM_DEVICE_INFO *response_data;
5086 int rc = 0;
5087 int bytes_returned = 0;
5088 __u16 params, byte_count;
5089
Joe Perchesb6b38f72010-04-21 03:50:45 +00005090 cFYI(1, "In QFSDeviceInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005091QFSDeviceRetry:
5092 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5093 (void **) &pSMBr);
5094 if (rc)
5095 return rc;
5096
5097 params = 2; /* level */
5098 pSMB->TotalDataCount = 0;
5099 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005100 /* BB find exact max SMB PDU from sess structure BB */
5101 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005102 pSMB->MaxSetupCount = 0;
5103 pSMB->Reserved = 0;
5104 pSMB->Flags = 0;
5105 pSMB->Timeout = 0;
5106 pSMB->Reserved2 = 0;
5107 byte_count = params + 1 /* pad */ ;
5108 pSMB->TotalParameterCount = cpu_to_le16(params);
5109 pSMB->ParameterCount = pSMB->TotalParameterCount;
5110 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005111 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005112
5113 pSMB->DataCount = 0;
5114 pSMB->DataOffset = 0;
5115 pSMB->SetupCount = 1;
5116 pSMB->Reserved3 = 0;
5117 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5118 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005119 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005120 pSMB->ByteCount = cpu_to_le16(byte_count);
5121
5122 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5123 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5124 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005125 cFYI(1, "Send error in QFSDeviceInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005126 } else { /* decode response */
5127 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5128
Jeff Layton820a8032011-05-04 08:05:26 -04005129 if (rc || get_bcc(&pSMBr->hdr) <
5130 sizeof(FILE_SYSTEM_DEVICE_INFO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005131 rc = -EIO; /* bad smb */
5132 else {
5133 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5134 response_data =
Steve French737b7582005-04-28 22:41:06 -07005135 (FILE_SYSTEM_DEVICE_INFO *)
5136 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07005137 data_offset);
5138 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005139 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005140 }
5141 }
5142 cifs_buf_release(pSMB);
5143
5144 if (rc == -EAGAIN)
5145 goto QFSDeviceRetry;
5146
5147 return rc;
5148}
5149
5150int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005151CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005152{
5153/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
5154 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5155 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5156 FILE_SYSTEM_UNIX_INFO *response_data;
5157 int rc = 0;
5158 int bytes_returned = 0;
5159 __u16 params, byte_count;
5160
Joe Perchesb6b38f72010-04-21 03:50:45 +00005161 cFYI(1, "In QFSUnixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005162QFSUnixRetry:
Jeff Laytonf5695992010-09-29 15:27:08 -04005163 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5164 (void **) &pSMB, (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005165 if (rc)
5166 return rc;
5167
5168 params = 2; /* level */
5169 pSMB->TotalDataCount = 0;
5170 pSMB->DataCount = 0;
5171 pSMB->DataOffset = 0;
5172 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005173 /* BB find exact max SMB PDU from sess structure BB */
5174 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005175 pSMB->MaxSetupCount = 0;
5176 pSMB->Reserved = 0;
5177 pSMB->Flags = 0;
5178 pSMB->Timeout = 0;
5179 pSMB->Reserved2 = 0;
5180 byte_count = params + 1 /* pad */ ;
5181 pSMB->ParameterCount = cpu_to_le16(params);
5182 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005183 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5184 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005185 pSMB->SetupCount = 1;
5186 pSMB->Reserved3 = 0;
5187 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5188 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005189 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005190 pSMB->ByteCount = cpu_to_le16(byte_count);
5191
5192 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5193 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5194 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005195 cERROR(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005196 } else { /* decode response */
5197 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5198
Jeff Layton820a8032011-05-04 08:05:26 -04005199 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005200 rc = -EIO; /* bad smb */
5201 } else {
5202 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5203 response_data =
5204 (FILE_SYSTEM_UNIX_INFO
5205 *) (((char *) &pSMBr->hdr.Protocol) +
5206 data_offset);
5207 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005208 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005209 }
5210 }
5211 cifs_buf_release(pSMB);
5212
5213 if (rc == -EAGAIN)
5214 goto QFSUnixRetry;
5215
5216
5217 return rc;
5218}
5219
Jeremy Allisonac670552005-06-22 17:26:35 -07005220int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005221CIFSSMBSetFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07005222{
5223/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
5224 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
5225 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
5226 int rc = 0;
5227 int bytes_returned = 0;
5228 __u16 params, param_offset, offset, byte_count;
5229
Joe Perchesb6b38f72010-04-21 03:50:45 +00005230 cFYI(1, "In SETFSUnixInfo");
Jeremy Allisonac670552005-06-22 17:26:35 -07005231SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00005232 /* BB switch to small buf init to save memory */
Jeff Laytonf5695992010-09-29 15:27:08 -04005233 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5234 (void **) &pSMB, (void **) &pSMBr);
Jeremy Allisonac670552005-06-22 17:26:35 -07005235 if (rc)
5236 return rc;
5237
5238 params = 4; /* 2 bytes zero followed by info level. */
5239 pSMB->MaxSetupCount = 0;
5240 pSMB->Reserved = 0;
5241 pSMB->Flags = 0;
5242 pSMB->Timeout = 0;
5243 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00005244 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
5245 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07005246 offset = param_offset + params;
5247
5248 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00005249 /* BB find exact max SMB PDU from sess structure BB */
5250 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07005251 pSMB->SetupCount = 1;
5252 pSMB->Reserved3 = 0;
5253 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
5254 byte_count = 1 /* pad */ + params + 12;
5255
5256 pSMB->DataCount = cpu_to_le16(12);
5257 pSMB->ParameterCount = cpu_to_le16(params);
5258 pSMB->TotalDataCount = pSMB->DataCount;
5259 pSMB->TotalParameterCount = pSMB->ParameterCount;
5260 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5261 pSMB->DataOffset = cpu_to_le16(offset);
5262
5263 /* Params. */
5264 pSMB->FileNum = 0;
5265 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
5266
5267 /* Data. */
5268 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
5269 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
5270 pSMB->ClientUnixCap = cpu_to_le64(cap);
5271
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005272 inc_rfc1001_len(pSMB, byte_count);
Jeremy Allisonac670552005-06-22 17:26:35 -07005273 pSMB->ByteCount = cpu_to_le16(byte_count);
5274
5275 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5276 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5277 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005278 cERROR(1, "Send error in SETFSUnixInfo = %d", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07005279 } else { /* decode response */
5280 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00005281 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07005282 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07005283 }
5284 cifs_buf_release(pSMB);
5285
5286 if (rc == -EAGAIN)
5287 goto SETFSUnixRetry;
5288
5289 return rc;
5290}
5291
5292
Linus Torvalds1da177e2005-04-16 15:20:36 -07005293
5294int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005295CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon,
Steve French737b7582005-04-28 22:41:06 -07005296 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005297{
5298/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
5299 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5300 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5301 FILE_SYSTEM_POSIX_INFO *response_data;
5302 int rc = 0;
5303 int bytes_returned = 0;
5304 __u16 params, byte_count;
5305
Joe Perchesb6b38f72010-04-21 03:50:45 +00005306 cFYI(1, "In QFSPosixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005307QFSPosixRetry:
5308 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5309 (void **) &pSMBr);
5310 if (rc)
5311 return rc;
5312
5313 params = 2; /* level */
5314 pSMB->TotalDataCount = 0;
5315 pSMB->DataCount = 0;
5316 pSMB->DataOffset = 0;
5317 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005318 /* BB find exact max SMB PDU from sess structure BB */
5319 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005320 pSMB->MaxSetupCount = 0;
5321 pSMB->Reserved = 0;
5322 pSMB->Flags = 0;
5323 pSMB->Timeout = 0;
5324 pSMB->Reserved2 = 0;
5325 byte_count = params + 1 /* pad */ ;
5326 pSMB->ParameterCount = cpu_to_le16(params);
5327 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005328 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5329 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005330 pSMB->SetupCount = 1;
5331 pSMB->Reserved3 = 0;
5332 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5333 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005334 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005335 pSMB->ByteCount = cpu_to_le16(byte_count);
5336
5337 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5338 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5339 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005340 cFYI(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005341 } else { /* decode response */
5342 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5343
Jeff Layton820a8032011-05-04 08:05:26 -04005344 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005345 rc = -EIO; /* bad smb */
5346 } else {
5347 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5348 response_data =
5349 (FILE_SYSTEM_POSIX_INFO
5350 *) (((char *) &pSMBr->hdr.Protocol) +
5351 data_offset);
5352 FSData->f_bsize =
5353 le32_to_cpu(response_data->BlockSize);
5354 FSData->f_blocks =
5355 le64_to_cpu(response_data->TotalBlocks);
5356 FSData->f_bfree =
5357 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00005358 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005359 FSData->f_bavail = FSData->f_bfree;
5360 } else {
5361 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00005362 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005363 }
Steve French790fe572007-07-07 19:25:05 +00005364 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005365 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00005366 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00005367 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005368 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00005369 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005370 }
5371 }
5372 cifs_buf_release(pSMB);
5373
5374 if (rc == -EAGAIN)
5375 goto QFSPosixRetry;
5376
5377 return rc;
5378}
5379
5380
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005381/*
5382 * We can not use write of zero bytes trick to set file size due to need for
5383 * large file support. Also note that this SetPathInfo is preferred to
5384 * SetFileInfo based method in next routine which is only needed to work around
5385 * a sharing violation bugin Samba which this routine can run into.
5386 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005387int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005388CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005389 const char *file_name, __u64 size, struct cifs_sb_info *cifs_sb,
5390 bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005391{
5392 struct smb_com_transaction2_spi_req *pSMB = NULL;
5393 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5394 struct file_end_of_file_info *parm_data;
5395 int name_len;
5396 int rc = 0;
5397 int bytes_returned = 0;
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005398 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
5399
Linus Torvalds1da177e2005-04-16 15:20:36 -07005400 __u16 params, byte_count, data_count, param_offset, offset;
5401
Joe Perchesb6b38f72010-04-21 03:50:45 +00005402 cFYI(1, "In SetEOF");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005403SetEOFRetry:
5404 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5405 (void **) &pSMBr);
5406 if (rc)
5407 return rc;
5408
5409 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5410 name_len =
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005411 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
5412 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005413 name_len++; /* trailing null */
5414 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005415 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005416 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005417 name_len++; /* trailing null */
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005418 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005419 }
5420 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005421 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005422 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07005423 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005424 pSMB->MaxSetupCount = 0;
5425 pSMB->Reserved = 0;
5426 pSMB->Flags = 0;
5427 pSMB->Timeout = 0;
5428 pSMB->Reserved2 = 0;
5429 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005430 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005431 offset = param_offset + params;
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005432 if (set_allocation) {
Steve French50c2f752007-07-13 00:33:32 +00005433 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5434 pSMB->InformationLevel =
5435 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5436 else
5437 pSMB->InformationLevel =
5438 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5439 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005440 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5441 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005442 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005443 else
5444 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005445 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005446 }
5447
5448 parm_data =
5449 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
5450 offset);
5451 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5452 pSMB->DataOffset = cpu_to_le16(offset);
5453 pSMB->SetupCount = 1;
5454 pSMB->Reserved3 = 0;
5455 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5456 byte_count = 3 /* pad */ + params + data_count;
5457 pSMB->DataCount = cpu_to_le16(data_count);
5458 pSMB->TotalDataCount = pSMB->DataCount;
5459 pSMB->ParameterCount = cpu_to_le16(params);
5460 pSMB->TotalParameterCount = pSMB->ParameterCount;
5461 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005462 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005463 parm_data->FileSize = cpu_to_le64(size);
5464 pSMB->ByteCount = cpu_to_le16(byte_count);
5465 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5466 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005467 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005468 cFYI(1, "SetPathInfo (file size) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005469
5470 cifs_buf_release(pSMB);
5471
5472 if (rc == -EAGAIN)
5473 goto SetEOFRetry;
5474
5475 return rc;
5476}
5477
5478int
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005479CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
5480 struct cifsFileInfo *cfile, __u64 size, bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005481{
5482 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005483 struct file_end_of_file_info *parm_data;
5484 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005485 __u16 params, param_offset, offset, byte_count, count;
5486
Joe Perchesb6b38f72010-04-21 03:50:45 +00005487 cFYI(1, "SetFileSize (via SetFileInfo) %lld",
5488 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07005489 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5490
Linus Torvalds1da177e2005-04-16 15:20:36 -07005491 if (rc)
5492 return rc;
5493
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005494 pSMB->hdr.Pid = cpu_to_le16((__u16)cfile->pid);
5495 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(cfile->pid >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005496
Linus Torvalds1da177e2005-04-16 15:20:36 -07005497 params = 6;
5498 pSMB->MaxSetupCount = 0;
5499 pSMB->Reserved = 0;
5500 pSMB->Flags = 0;
5501 pSMB->Timeout = 0;
5502 pSMB->Reserved2 = 0;
5503 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5504 offset = param_offset + params;
5505
Linus Torvalds1da177e2005-04-16 15:20:36 -07005506 count = sizeof(struct file_end_of_file_info);
5507 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005508 /* BB find exact max SMB PDU from sess structure BB */
5509 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005510 pSMB->SetupCount = 1;
5511 pSMB->Reserved3 = 0;
5512 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5513 byte_count = 3 /* pad */ + params + count;
5514 pSMB->DataCount = cpu_to_le16(count);
5515 pSMB->ParameterCount = cpu_to_le16(params);
5516 pSMB->TotalDataCount = pSMB->DataCount;
5517 pSMB->TotalParameterCount = pSMB->ParameterCount;
5518 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5519 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00005520 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
5521 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005522 pSMB->DataOffset = cpu_to_le16(offset);
5523 parm_data->FileSize = cpu_to_le64(size);
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005524 pSMB->Fid = cfile->fid.netfid;
5525 if (set_allocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005526 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5527 pSMB->InformationLevel =
5528 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5529 else
5530 pSMB->InformationLevel =
5531 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00005532 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005533 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5534 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005535 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005536 else
5537 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005538 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005539 }
5540 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005541 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005542 pSMB->ByteCount = cpu_to_le16(byte_count);
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005543 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005544 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005545 cFYI(1, "Send error in SetFileInfo (SetFileSize) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005546 }
5547
Steve French50c2f752007-07-13 00:33:32 +00005548 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005549 since file handle passed in no longer valid */
5550
5551 return rc;
5552}
5553
Steve French50c2f752007-07-13 00:33:32 +00005554/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07005555 an open handle, rather than by pathname - this is awkward due to
5556 potential access conflicts on the open, but it is unavoidable for these
5557 old servers since the only other choice is to go from 100 nanosecond DCE
5558 time and resort to the original setpathinfo level which takes the ancient
5559 DOS time format with 2 second granularity */
5560int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005561CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005562 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005563{
5564 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005565 char *data_offset;
5566 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005567 __u16 params, param_offset, offset, byte_count, count;
5568
Joe Perchesb6b38f72010-04-21 03:50:45 +00005569 cFYI(1, "Set Times (via SetFileInfo)");
Steve Frenchcd634992005-04-28 22:41:10 -07005570 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5571
Linus Torvalds1da177e2005-04-16 15:20:36 -07005572 if (rc)
5573 return rc;
5574
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005575 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5576 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005577
Linus Torvalds1da177e2005-04-16 15:20:36 -07005578 params = 6;
5579 pSMB->MaxSetupCount = 0;
5580 pSMB->Reserved = 0;
5581 pSMB->Flags = 0;
5582 pSMB->Timeout = 0;
5583 pSMB->Reserved2 = 0;
5584 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5585 offset = param_offset + params;
5586
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005587 data_offset = (char *)pSMB +
5588 offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005589
Steve French26f57362007-08-30 22:09:15 +00005590 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005591 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005592 /* BB find max SMB PDU from sess */
5593 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005594 pSMB->SetupCount = 1;
5595 pSMB->Reserved3 = 0;
5596 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5597 byte_count = 3 /* pad */ + params + count;
5598 pSMB->DataCount = cpu_to_le16(count);
5599 pSMB->ParameterCount = cpu_to_le16(params);
5600 pSMB->TotalDataCount = pSMB->DataCount;
5601 pSMB->TotalParameterCount = pSMB->ParameterCount;
5602 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5603 pSMB->DataOffset = cpu_to_le16(offset);
5604 pSMB->Fid = fid;
5605 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5606 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5607 else
5608 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5609 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005610 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005611 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005612 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005613 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005614 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005615 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005616
Steve French50c2f752007-07-13 00:33:32 +00005617 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005618 since file handle passed in no longer valid */
5619
5620 return rc;
5621}
5622
Jeff Layton6d22f092008-09-23 11:48:35 -04005623int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005624CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6d22f092008-09-23 11:48:35 -04005625 bool delete_file, __u16 fid, __u32 pid_of_opener)
5626{
5627 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5628 char *data_offset;
5629 int rc = 0;
5630 __u16 params, param_offset, offset, byte_count, count;
5631
Joe Perchesb6b38f72010-04-21 03:50:45 +00005632 cFYI(1, "Set File Disposition (via SetFileInfo)");
Jeff Layton6d22f092008-09-23 11:48:35 -04005633 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5634
5635 if (rc)
5636 return rc;
5637
5638 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5639 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5640
5641 params = 6;
5642 pSMB->MaxSetupCount = 0;
5643 pSMB->Reserved = 0;
5644 pSMB->Flags = 0;
5645 pSMB->Timeout = 0;
5646 pSMB->Reserved2 = 0;
5647 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5648 offset = param_offset + params;
5649
5650 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5651
5652 count = 1;
5653 pSMB->MaxParameterCount = cpu_to_le16(2);
5654 /* BB find max SMB PDU from sess */
5655 pSMB->MaxDataCount = cpu_to_le16(1000);
5656 pSMB->SetupCount = 1;
5657 pSMB->Reserved3 = 0;
5658 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5659 byte_count = 3 /* pad */ + params + count;
5660 pSMB->DataCount = cpu_to_le16(count);
5661 pSMB->ParameterCount = cpu_to_le16(params);
5662 pSMB->TotalDataCount = pSMB->DataCount;
5663 pSMB->TotalParameterCount = pSMB->ParameterCount;
5664 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5665 pSMB->DataOffset = cpu_to_le16(offset);
5666 pSMB->Fid = fid;
5667 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5668 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005669 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton6d22f092008-09-23 11:48:35 -04005670 pSMB->ByteCount = cpu_to_le16(byte_count);
5671 *data_offset = delete_file ? 1 : 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005672 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Jeff Layton6d22f092008-09-23 11:48:35 -04005673 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005674 cFYI(1, "Send error in SetFileDisposition = %d", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005675
5676 return rc;
5677}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005678
5679int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005680CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6fc000e2008-08-02 07:26:12 -04005681 const char *fileName, const FILE_BASIC_INFO *data,
5682 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005683{
5684 TRANSACTION2_SPI_REQ *pSMB = NULL;
5685 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5686 int name_len;
5687 int rc = 0;
5688 int bytes_returned = 0;
5689 char *data_offset;
5690 __u16 params, param_offset, offset, byte_count, count;
5691
Joe Perchesb6b38f72010-04-21 03:50:45 +00005692 cFYI(1, "In SetTimes");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005693
5694SetTimesRetry:
5695 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5696 (void **) &pSMBr);
5697 if (rc)
5698 return rc;
5699
5700 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5701 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005702 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5703 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005704 name_len++; /* trailing null */
5705 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005706 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005707 name_len = strnlen(fileName, PATH_MAX);
5708 name_len++; /* trailing null */
5709 strncpy(pSMB->FileName, fileName, name_len);
5710 }
5711
5712 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005713 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005714 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005715 /* BB find max SMB PDU from sess structure BB */
5716 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005717 pSMB->MaxSetupCount = 0;
5718 pSMB->Reserved = 0;
5719 pSMB->Flags = 0;
5720 pSMB->Timeout = 0;
5721 pSMB->Reserved2 = 0;
5722 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005723 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005724 offset = param_offset + params;
5725 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5726 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5727 pSMB->DataOffset = cpu_to_le16(offset);
5728 pSMB->SetupCount = 1;
5729 pSMB->Reserved3 = 0;
5730 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5731 byte_count = 3 /* pad */ + params + count;
5732
5733 pSMB->DataCount = cpu_to_le16(count);
5734 pSMB->ParameterCount = cpu_to_le16(params);
5735 pSMB->TotalDataCount = pSMB->DataCount;
5736 pSMB->TotalParameterCount = pSMB->ParameterCount;
5737 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5738 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5739 else
5740 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5741 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005742 inc_rfc1001_len(pSMB, byte_count);
Steve French26f57362007-08-30 22:09:15 +00005743 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005744 pSMB->ByteCount = cpu_to_le16(byte_count);
5745 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5746 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005747 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005748 cFYI(1, "SetPathInfo (times) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005749
5750 cifs_buf_release(pSMB);
5751
5752 if (rc == -EAGAIN)
5753 goto SetTimesRetry;
5754
5755 return rc;
5756}
5757
5758/* Can not be used to set time stamps yet (due to old DOS time format) */
5759/* Can be used to set attributes */
5760#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5761 handling it anyway and NT4 was what we thought it would be needed for
5762 Do not delete it until we prove whether needed for Win9x though */
5763int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005764CIFSSMBSetAttrLegacy(unsigned int xid, struct cifs_tcon *tcon, char *fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005765 __u16 dos_attrs, const struct nls_table *nls_codepage)
5766{
5767 SETATTR_REQ *pSMB = NULL;
5768 SETATTR_RSP *pSMBr = NULL;
5769 int rc = 0;
5770 int bytes_returned;
5771 int name_len;
5772
Joe Perchesb6b38f72010-04-21 03:50:45 +00005773 cFYI(1, "In SetAttrLegacy");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005774
5775SetAttrLgcyRetry:
5776 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5777 (void **) &pSMBr);
5778 if (rc)
5779 return rc;
5780
5781 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5782 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005783 ConvertToUTF16((__le16 *) pSMB->fileName, fileName,
5784 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005785 name_len++; /* trailing null */
5786 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005787 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005788 name_len = strnlen(fileName, PATH_MAX);
5789 name_len++; /* trailing null */
5790 strncpy(pSMB->fileName, fileName, name_len);
5791 }
5792 pSMB->attr = cpu_to_le16(dos_attrs);
5793 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005794 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005795 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5796 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5797 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005798 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005799 cFYI(1, "Error in LegacySetAttr = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005800
5801 cifs_buf_release(pSMB);
5802
5803 if (rc == -EAGAIN)
5804 goto SetAttrLgcyRetry;
5805
5806 return rc;
5807}
5808#endif /* temporarily unneeded SetAttr legacy function */
5809
Jeff Layton654cf142009-07-09 20:02:49 -04005810static void
5811cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5812 const struct cifs_unix_set_info_args *args)
5813{
5814 u64 mode = args->mode;
5815
5816 /*
5817 * Samba server ignores set of file size to zero due to bugs in some
5818 * older clients, but we should be precise - we use SetFileSize to
5819 * set file size and do not want to truncate file size to zero
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005820 * accidentally as happened on one Samba server beta by putting
Jeff Layton654cf142009-07-09 20:02:49 -04005821 * zero instead of -1 here
5822 */
5823 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5824 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5825 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5826 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5827 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5828 data_offset->Uid = cpu_to_le64(args->uid);
5829 data_offset->Gid = cpu_to_le64(args->gid);
5830 /* better to leave device as zero when it is */
5831 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5832 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5833 data_offset->Permissions = cpu_to_le64(mode);
5834
5835 if (S_ISREG(mode))
5836 data_offset->Type = cpu_to_le32(UNIX_FILE);
5837 else if (S_ISDIR(mode))
5838 data_offset->Type = cpu_to_le32(UNIX_DIR);
5839 else if (S_ISLNK(mode))
5840 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5841 else if (S_ISCHR(mode))
5842 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5843 else if (S_ISBLK(mode))
5844 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5845 else if (S_ISFIFO(mode))
5846 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5847 else if (S_ISSOCK(mode))
5848 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5849}
5850
Linus Torvalds1da177e2005-04-16 15:20:36 -07005851int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005852CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005853 const struct cifs_unix_set_info_args *args,
5854 u16 fid, u32 pid_of_opener)
5855{
5856 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005857 char *data_offset;
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005858 int rc = 0;
5859 u16 params, param_offset, offset, byte_count, count;
5860
Joe Perchesb6b38f72010-04-21 03:50:45 +00005861 cFYI(1, "Set Unix Info (via SetFileInfo)");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005862 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5863
5864 if (rc)
5865 return rc;
5866
5867 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5868 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5869
5870 params = 6;
5871 pSMB->MaxSetupCount = 0;
5872 pSMB->Reserved = 0;
5873 pSMB->Flags = 0;
5874 pSMB->Timeout = 0;
5875 pSMB->Reserved2 = 0;
5876 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5877 offset = param_offset + params;
5878
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005879 data_offset = (char *)pSMB +
5880 offsetof(struct smb_hdr, Protocol) + offset;
5881
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005882 count = sizeof(FILE_UNIX_BASIC_INFO);
5883
5884 pSMB->MaxParameterCount = cpu_to_le16(2);
5885 /* BB find max SMB PDU from sess */
5886 pSMB->MaxDataCount = cpu_to_le16(1000);
5887 pSMB->SetupCount = 1;
5888 pSMB->Reserved3 = 0;
5889 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5890 byte_count = 3 /* pad */ + params + count;
5891 pSMB->DataCount = cpu_to_le16(count);
5892 pSMB->ParameterCount = cpu_to_le16(params);
5893 pSMB->TotalDataCount = pSMB->DataCount;
5894 pSMB->TotalParameterCount = pSMB->ParameterCount;
5895 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5896 pSMB->DataOffset = cpu_to_le16(offset);
5897 pSMB->Fid = fid;
5898 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5899 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005900 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005901 pSMB->ByteCount = cpu_to_le16(byte_count);
5902
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005903 cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005904
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005905 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005906 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005907 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005908
5909 /* Note: On -EAGAIN error only caller can retry on handle based calls
5910 since file handle passed in no longer valid */
5911
5912 return rc;
5913}
5914
5915int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005916CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005917 const char *file_name,
Jeff Layton01ea95e2009-07-09 20:02:49 -04005918 const struct cifs_unix_set_info_args *args,
5919 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005920{
5921 TRANSACTION2_SPI_REQ *pSMB = NULL;
5922 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5923 int name_len;
5924 int rc = 0;
5925 int bytes_returned = 0;
5926 FILE_UNIX_BASIC_INFO *data_offset;
5927 __u16 params, param_offset, offset, count, byte_count;
5928
Joe Perchesb6b38f72010-04-21 03:50:45 +00005929 cFYI(1, "In SetUID/GID/Mode");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005930setPermsRetry:
5931 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5932 (void **) &pSMBr);
5933 if (rc)
5934 return rc;
5935
5936 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5937 name_len =
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005938 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06005939 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005940 name_len++; /* trailing null */
5941 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005942 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005943 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005944 name_len++; /* trailing null */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005945 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005946 }
5947
5948 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005949 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005950 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005951 /* BB find max SMB PDU from sess structure BB */
5952 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005953 pSMB->MaxSetupCount = 0;
5954 pSMB->Reserved = 0;
5955 pSMB->Flags = 0;
5956 pSMB->Timeout = 0;
5957 pSMB->Reserved2 = 0;
5958 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005959 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005960 offset = param_offset + params;
5961 data_offset =
5962 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5963 offset);
5964 memset(data_offset, 0, count);
5965 pSMB->DataOffset = cpu_to_le16(offset);
5966 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5967 pSMB->SetupCount = 1;
5968 pSMB->Reserved3 = 0;
5969 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5970 byte_count = 3 /* pad */ + params + count;
5971 pSMB->ParameterCount = cpu_to_le16(params);
5972 pSMB->DataCount = cpu_to_le16(count);
5973 pSMB->TotalParameterCount = pSMB->ParameterCount;
5974 pSMB->TotalDataCount = pSMB->DataCount;
5975 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5976 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005977 inc_rfc1001_len(pSMB, byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005978
Jeff Layton654cf142009-07-09 20:02:49 -04005979 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005980
5981 pSMB->ByteCount = cpu_to_le16(byte_count);
5982 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5983 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005984 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005985 cFYI(1, "SetPathInfo (perms) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005986
Steve French0d817bc2008-05-22 02:02:03 +00005987 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005988 if (rc == -EAGAIN)
5989 goto setPermsRetry;
5990 return rc;
5991}
5992
Linus Torvalds1da177e2005-04-16 15:20:36 -07005993#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05005994/*
5995 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
5996 * function used by listxattr and getxattr type calls. When ea_name is set,
5997 * it looks for that attribute name and stuffs that value into the EAData
5998 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
5999 * buffer. In both cases, the return value is either the length of the
6000 * resulting data or a negative error code. If EAData is a NULL pointer then
6001 * the data isn't copied to it, but the length is returned.
6002 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006003ssize_t
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006004CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05006005 const unsigned char *searchName, const unsigned char *ea_name,
6006 char *EAData, size_t buf_size,
6007 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006008{
6009 /* BB assumes one setup word */
6010 TRANSACTION2_QPI_REQ *pSMB = NULL;
6011 TRANSACTION2_QPI_RSP *pSMBr = NULL;
6012 int rc = 0;
6013 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05006014 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006015 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00006016 struct fea *temp_fea;
6017 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006018 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006019 __u16 params, byte_count, data_offset;
Jeff Layton5980fc92011-07-28 12:48:26 -04006020 unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006021
Joe Perchesb6b38f72010-04-21 03:50:45 +00006022 cFYI(1, "In Query All EAs path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006023QAllEAsRetry:
6024 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6025 (void **) &pSMBr);
6026 if (rc)
6027 return rc;
6028
6029 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05006030 list_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006031 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
6032 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05006033 list_len++; /* trailing null */
6034 list_len *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006035 } else { /* BB improve the check for buffer overruns BB */
Jeff Layton6e462b92010-02-10 16:18:26 -05006036 list_len = strnlen(searchName, PATH_MAX);
6037 list_len++; /* trailing null */
6038 strncpy(pSMB->FileName, searchName, list_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006039 }
6040
Jeff Layton6e462b92010-02-10 16:18:26 -05006041 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006042 pSMB->TotalDataCount = 0;
6043 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006044 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05006045 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006046 pSMB->MaxSetupCount = 0;
6047 pSMB->Reserved = 0;
6048 pSMB->Flags = 0;
6049 pSMB->Timeout = 0;
6050 pSMB->Reserved2 = 0;
6051 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00006052 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006053 pSMB->DataCount = 0;
6054 pSMB->DataOffset = 0;
6055 pSMB->SetupCount = 1;
6056 pSMB->Reserved3 = 0;
6057 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
6058 byte_count = params + 1 /* pad */ ;
6059 pSMB->TotalParameterCount = cpu_to_le16(params);
6060 pSMB->ParameterCount = pSMB->TotalParameterCount;
6061 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
6062 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006063 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006064 pSMB->ByteCount = cpu_to_le16(byte_count);
6065
6066 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6067 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6068 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006069 cFYI(1, "Send error in QueryAllEAs = %d", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05006070 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006071 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006072
6073
6074 /* BB also check enough total bytes returned */
6075 /* BB we need to improve the validity checking
6076 of these trans2 responses */
6077
6078 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Jeff Layton820a8032011-05-04 08:05:26 -04006079 if (rc || get_bcc(&pSMBr->hdr) < 4) {
Jeff Laytonf0d38682010-02-10 16:18:26 -05006080 rc = -EIO; /* bad smb */
6081 goto QAllEAsOut;
6082 }
6083
6084 /* check that length of list is not more than bcc */
6085 /* check that each entry does not go beyond length
6086 of list */
6087 /* check that each element of each entry does not
6088 go beyond end of list */
6089 /* validate_trans2_offsets() */
6090 /* BB check if start of smb + data_offset > &bcc+ bcc */
6091
6092 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
6093 ea_response_data = (struct fealist *)
6094 (((char *) &pSMBr->hdr.Protocol) + data_offset);
6095
Jeff Layton6e462b92010-02-10 16:18:26 -05006096 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesb6b38f72010-04-21 03:50:45 +00006097 cFYI(1, "ea length %d", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05006098 if (list_len <= 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006099 cFYI(1, "empty EA list returned from server");
Jeff Laytonf0d38682010-02-10 16:18:26 -05006100 goto QAllEAsOut;
6101 }
6102
Jeff Layton0cd126b2010-02-10 16:18:26 -05006103 /* make sure list_len doesn't go past end of SMB */
Jeff Layton690c5222011-01-20 13:36:51 -05006104 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
Jeff Layton0cd126b2010-02-10 16:18:26 -05006105 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006106 cFYI(1, "EA list appears to go beyond SMB");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006107 rc = -EIO;
6108 goto QAllEAsOut;
6109 }
6110
Jeff Laytonf0d38682010-02-10 16:18:26 -05006111 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05006112 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006113 temp_fea = ea_response_data->list;
6114 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05006115 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00006116 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006117 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006118
Jeff Layton6e462b92010-02-10 16:18:26 -05006119 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006120 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006121 /* make sure we can read name_len and value_len */
6122 if (list_len < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006123 cFYI(1, "EA entry goes beyond length of list");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006124 rc = -EIO;
6125 goto QAllEAsOut;
6126 }
6127
6128 name_len = temp_fea->name_len;
6129 value_len = le16_to_cpu(temp_fea->value_len);
6130 list_len -= name_len + 1 + value_len;
6131 if (list_len < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006132 cFYI(1, "EA entry goes beyond length of list");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006133 rc = -EIO;
6134 goto QAllEAsOut;
6135 }
6136
Jeff Layton31c05192010-02-10 16:18:26 -05006137 if (ea_name) {
Jeff Layton91d065c2011-07-26 18:23:47 -04006138 if (ea_name_len == name_len &&
Jeff Laytonac423442011-10-11 06:41:32 -04006139 memcmp(ea_name, temp_ptr, name_len) == 0) {
Jeff Layton31c05192010-02-10 16:18:26 -05006140 temp_ptr += name_len + 1;
6141 rc = value_len;
6142 if (buf_size == 0)
6143 goto QAllEAsOut;
6144 if ((size_t)value_len > buf_size) {
6145 rc = -ERANGE;
6146 goto QAllEAsOut;
6147 }
6148 memcpy(EAData, temp_ptr, value_len);
6149 goto QAllEAsOut;
6150 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006151 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05006152 /* account for prefix user. and trailing null */
6153 rc += (5 + 1 + name_len);
6154 if (rc < (int) buf_size) {
6155 memcpy(EAData, "user.", 5);
6156 EAData += 5;
6157 memcpy(EAData, temp_ptr, name_len);
6158 EAData += name_len;
6159 /* null terminate name */
6160 *EAData = 0;
6161 ++EAData;
6162 } else if (buf_size == 0) {
6163 /* skip copy - calc size only */
6164 } else {
6165 /* stop before overrun buffer */
6166 rc = -ERANGE;
6167 break;
6168 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006169 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05006170 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006171 temp_fea = (struct fea *)temp_ptr;
6172 }
6173
Jeff Layton31c05192010-02-10 16:18:26 -05006174 /* didn't find the named attribute */
6175 if (ea_name)
6176 rc = -ENODATA;
6177
Jeff Laytonf0d38682010-02-10 16:18:26 -05006178QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00006179 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006180 if (rc == -EAGAIN)
6181 goto QAllEAsRetry;
6182
6183 return (ssize_t)rc;
6184}
6185
Linus Torvalds1da177e2005-04-16 15:20:36 -07006186int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006187CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
6188 const char *fileName, const char *ea_name, const void *ea_value,
Steve French50c2f752007-07-13 00:33:32 +00006189 const __u16 ea_value_len, const struct nls_table *nls_codepage,
6190 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006191{
6192 struct smb_com_transaction2_spi_req *pSMB = NULL;
6193 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
6194 struct fealist *parm_data;
6195 int name_len;
6196 int rc = 0;
6197 int bytes_returned = 0;
6198 __u16 params, param_offset, byte_count, offset, count;
6199
Joe Perchesb6b38f72010-04-21 03:50:45 +00006200 cFYI(1, "In SetEA");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006201SetEARetry:
6202 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6203 (void **) &pSMBr);
6204 if (rc)
6205 return rc;
6206
6207 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6208 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006209 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
6210 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006211 name_len++; /* trailing null */
6212 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00006213 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006214 name_len = strnlen(fileName, PATH_MAX);
6215 name_len++; /* trailing null */
6216 strncpy(pSMB->FileName, fileName, name_len);
6217 }
6218
6219 params = 6 + name_len;
6220
6221 /* done calculating parms using name_len of file name,
6222 now use name_len to calculate length of ea name
6223 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00006224 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006225 name_len = 0;
6226 else
Steve French50c2f752007-07-13 00:33:32 +00006227 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006228
Steve Frenchdae5dbd2007-12-30 23:49:57 +00006229 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006230 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006231 /* BB find max SMB PDU from sess */
6232 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006233 pSMB->MaxSetupCount = 0;
6234 pSMB->Reserved = 0;
6235 pSMB->Flags = 0;
6236 pSMB->Timeout = 0;
6237 pSMB->Reserved2 = 0;
6238 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006239 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006240 offset = param_offset + params;
6241 pSMB->InformationLevel =
6242 cpu_to_le16(SMB_SET_FILE_EA);
6243
6244 parm_data =
6245 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
6246 offset);
6247 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6248 pSMB->DataOffset = cpu_to_le16(offset);
6249 pSMB->SetupCount = 1;
6250 pSMB->Reserved3 = 0;
6251 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6252 byte_count = 3 /* pad */ + params + count;
6253 pSMB->DataCount = cpu_to_le16(count);
6254 parm_data->list_len = cpu_to_le32(count);
6255 parm_data->list[0].EA_flags = 0;
6256 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08006257 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006258 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00006259 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00006260 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006261 parm_data->list[0].name[name_len] = 0;
6262 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
6263 /* caller ensures that ea_value_len is less than 64K but
6264 we need to ensure that it fits within the smb */
6265
Steve French50c2f752007-07-13 00:33:32 +00006266 /*BB add length check to see if it would fit in
6267 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00006268 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
6269 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00006270 memcpy(parm_data->list[0].name+name_len+1,
6271 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006272
6273 pSMB->TotalDataCount = pSMB->DataCount;
6274 pSMB->ParameterCount = cpu_to_le16(params);
6275 pSMB->TotalParameterCount = pSMB->ParameterCount;
6276 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006277 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006278 pSMB->ByteCount = cpu_to_le16(byte_count);
6279 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6280 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006281 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00006282 cFYI(1, "SetPathInfo (EA) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006283
6284 cifs_buf_release(pSMB);
6285
6286 if (rc == -EAGAIN)
6287 goto SetEARetry;
6288
6289 return rc;
6290}
Linus Torvalds1da177e2005-04-16 15:20:36 -07006291#endif
Steve French0eff0e22011-02-24 05:39:23 +00006292
6293#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */
6294/*
6295 * Years ago the kernel added a "dnotify" function for Samba server,
6296 * to allow network clients (such as Windows) to display updated
6297 * lists of files in directory listings automatically when
6298 * files are added by one user when another user has the
6299 * same directory open on their desktop. The Linux cifs kernel
6300 * client hooked into the kernel side of this interface for
6301 * the same reason, but ironically when the VFS moved from
6302 * "dnotify" to "inotify" it became harder to plug in Linux
6303 * network file system clients (the most obvious use case
6304 * for notify interfaces is when multiple users can update
6305 * the contents of the same directory - exactly what network
6306 * file systems can do) although the server (Samba) could
6307 * still use it. For the short term we leave the worker
6308 * function ifdeffed out (below) until inotify is fixed
6309 * in the VFS to make it easier to plug in network file
6310 * system clients. If inotify turns out to be permanently
6311 * incompatible for network fs clients, we could instead simply
6312 * expose this config flag by adding a future cifs (and smb2) notify ioctl.
6313 */
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006314int CIFSSMBNotify(const unsigned int xid, struct cifs_tcon *tcon,
Steve French0eff0e22011-02-24 05:39:23 +00006315 const int notify_subdirs, const __u16 netfid,
6316 __u32 filter, struct file *pfile, int multishot,
6317 const struct nls_table *nls_codepage)
6318{
6319 int rc = 0;
6320 struct smb_com_transaction_change_notify_req *pSMB = NULL;
6321 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
6322 struct dir_notify_req *dnotify_req;
6323 int bytes_returned;
6324
6325 cFYI(1, "In CIFSSMBNotify for file handle %d", (int)netfid);
6326 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
6327 (void **) &pSMBr);
6328 if (rc)
6329 return rc;
6330
6331 pSMB->TotalParameterCount = 0 ;
6332 pSMB->TotalDataCount = 0;
6333 pSMB->MaxParameterCount = cpu_to_le32(2);
Jeff Laytonc974bef2011-10-11 06:41:32 -04006334 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Steve French0eff0e22011-02-24 05:39:23 +00006335 pSMB->MaxSetupCount = 4;
6336 pSMB->Reserved = 0;
6337 pSMB->ParameterOffset = 0;
6338 pSMB->DataCount = 0;
6339 pSMB->DataOffset = 0;
6340 pSMB->SetupCount = 4; /* single byte does not need le conversion */
6341 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
6342 pSMB->ParameterCount = pSMB->TotalParameterCount;
6343 if (notify_subdirs)
6344 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
6345 pSMB->Reserved2 = 0;
6346 pSMB->CompletionFilter = cpu_to_le32(filter);
6347 pSMB->Fid = netfid; /* file handle always le */
6348 pSMB->ByteCount = 0;
6349
6350 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6351 (struct smb_hdr *)pSMBr, &bytes_returned,
6352 CIFS_ASYNC_OP);
6353 if (rc) {
6354 cFYI(1, "Error in Notify = %d", rc);
6355 } else {
6356 /* Add file to outstanding requests */
6357 /* BB change to kmem cache alloc */
6358 dnotify_req = kmalloc(
6359 sizeof(struct dir_notify_req),
6360 GFP_KERNEL);
6361 if (dnotify_req) {
6362 dnotify_req->Pid = pSMB->hdr.Pid;
6363 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
6364 dnotify_req->Mid = pSMB->hdr.Mid;
6365 dnotify_req->Tid = pSMB->hdr.Tid;
6366 dnotify_req->Uid = pSMB->hdr.Uid;
6367 dnotify_req->netfid = netfid;
6368 dnotify_req->pfile = pfile;
6369 dnotify_req->filter = filter;
6370 dnotify_req->multishot = multishot;
6371 spin_lock(&GlobalMid_Lock);
6372 list_add_tail(&dnotify_req->lhead,
6373 &GlobalDnotifyReqList);
6374 spin_unlock(&GlobalMid_Lock);
6375 } else
6376 rc = -ENOMEM;
6377 }
6378 cifs_buf_release(pSMB);
6379 return rc;
6380}
6381#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */