blob: cd66b76e3282e7bfa8768c23a9ed211cacdeec40 [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
Jeff Laytone28bc5b2011-10-19 15:30:07 -040089/* Forward declarations */
90static void cifs_readv_complete(struct work_struct *work);
91
Linus Torvalds1da177e2005-04-16 15:20:36 -070092/* Mark as invalid, all open files on tree connections since they
93 were closed when session to server was lost */
Steve French96daf2b2011-05-27 04:34:02 +000094static void mark_open_files_invalid(struct cifs_tcon *pTcon)
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
100/* 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);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102 list_for_each_safe(tmp, tmp1, &pTcon->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);
Steve French09d1db52005-04-28 22:41:08 -0700108 /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
109 to this tcon */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110}
111
Jeff Layton9162ab22009-09-03 12:07:17 -0400112/* reconnect the socket, tcon, and smb session if needed */
113static int
Steve French96daf2b2011-05-27 04:34:02 +0000114cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
Jeff Layton9162ab22009-09-03 12:07:17 -0400115{
Jeff Laytonc4a55342011-07-28 12:40:36 -0400116 int rc;
Steve French96daf2b2011-05-27 04:34:02 +0000117 struct cifs_ses *ses;
Jeff Layton9162ab22009-09-03 12:07:17 -0400118 struct TCP_Server_Info *server;
119 struct nls_table *nls_codepage;
120
121 /*
122 * SMBs NegProt, SessSetup, uLogoff do not have tcon yet so check for
123 * tcp and smb session status done differently for those three - in the
124 * calling routine
125 */
126 if (!tcon)
127 return 0;
128
129 ses = tcon->ses;
130 server = ses->server;
131
132 /*
133 * only tree disconnect, open, and write, (and ulogoff which does not
134 * have tcon) are allowed as we start force umount
135 */
136 if (tcon->tidStatus == CifsExiting) {
137 if (smb_command != SMB_COM_WRITE_ANDX &&
138 smb_command != SMB_COM_OPEN_ANDX &&
139 smb_command != SMB_COM_TREE_DISCONNECT) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000140 cFYI(1, "can not send cmd %d while umounting",
141 smb_command);
Jeff Layton9162ab22009-09-03 12:07:17 -0400142 return -ENODEV;
143 }
144 }
145
Jeff Layton9162ab22009-09-03 12:07:17 -0400146 /*
147 * Give demultiplex thread up to 10 seconds to reconnect, should be
148 * greater than cifs socket timeout which is 7 seconds
149 */
150 while (server->tcpStatus == CifsNeedReconnect) {
151 wait_event_interruptible_timeout(server->response_q,
Steve Frenchfd88ce92011-04-12 01:01:14 +0000152 (server->tcpStatus != CifsNeedReconnect), 10 * HZ);
Jeff Layton9162ab22009-09-03 12:07:17 -0400153
Steve Frenchfd88ce92011-04-12 01:01:14 +0000154 /* are we still trying to reconnect? */
Jeff Layton9162ab22009-09-03 12:07:17 -0400155 if (server->tcpStatus != CifsNeedReconnect)
156 break;
157
158 /*
159 * on "soft" mounts we wait once. Hard mounts keep
160 * retrying until process is killed or server comes
161 * back on-line
162 */
Jeff Laytond4025392011-02-07 08:54:35 -0500163 if (!tcon->retry) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000164 cFYI(1, "gave up waiting on reconnect in smb_init");
Jeff Layton9162ab22009-09-03 12:07:17 -0400165 return -EHOSTDOWN;
166 }
167 }
168
169 if (!ses->need_reconnect && !tcon->need_reconnect)
170 return 0;
171
172 nls_codepage = load_nls_default();
173
174 /*
175 * need to prevent multiple threads trying to simultaneously
176 * reconnect the same SMB session
177 */
Steve Frenchd7b619c2010-02-25 05:36:46 +0000178 mutex_lock(&ses->session_mutex);
Jeff Layton198b5682010-04-24 07:57:48 -0400179 rc = cifs_negotiate_protocol(0, ses);
180 if (rc == 0 && ses->need_reconnect)
Jeff Layton9162ab22009-09-03 12:07:17 -0400181 rc = cifs_setup_session(0, ses, nls_codepage);
182
183 /* do we need to reconnect tcon? */
184 if (rc || !tcon->need_reconnect) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000185 mutex_unlock(&ses->session_mutex);
Jeff Layton9162ab22009-09-03 12:07:17 -0400186 goto out;
187 }
188
189 mark_open_files_invalid(tcon);
190 rc = CIFSTCon(0, ses, tcon->treeName, tcon, nls_codepage);
Steve Frenchd7b619c2010-02-25 05:36:46 +0000191 mutex_unlock(&ses->session_mutex);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000192 cFYI(1, "reconnect tcon rc = %d", rc);
Jeff Layton9162ab22009-09-03 12:07:17 -0400193
194 if (rc)
195 goto out;
196
197 /*
198 * FIXME: check if wsize needs updated due to negotiated smb buffer
199 * size shrinking
200 */
201 atomic_inc(&tconInfoReconnectCount);
202
203 /* tell server Unix caps we support */
204 if (ses->capabilities & CAP_UNIX)
205 reset_cifs_unix_caps(0, tcon, NULL, NULL);
206
207 /*
208 * Removed call to reopen open files here. It is safer (and faster) to
209 * reopen files one at a time as needed in read and write.
210 *
211 * FIXME: what about file locks? don't we need to reclaim them ASAP?
212 */
213
214out:
215 /*
216 * Check if handle based operation so we know whether we can continue
217 * or not without returning to caller to reset file handle
218 */
219 switch (smb_command) {
220 case SMB_COM_READ_ANDX:
221 case SMB_COM_WRITE_ANDX:
222 case SMB_COM_CLOSE:
223 case SMB_COM_FIND_CLOSE2:
224 case SMB_COM_LOCKING_ANDX:
225 rc = -EAGAIN;
226 }
227
228 unload_nls(nls_codepage);
229 return rc;
230}
231
Steve Frenchad7a2922008-02-07 23:25:02 +0000232/* Allocate and return pointer to an SMB request buffer, and set basic
233 SMB information in the SMB header. If the return code is zero, this
234 function must have filled in request_buf pointer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235static int
Steve French96daf2b2011-05-27 04:34:02 +0000236small_smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000237 void **request_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238{
Jeff Laytonf5695992010-09-29 15:27:08 -0400239 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240
Jeff Layton9162ab22009-09-03 12:07:17 -0400241 rc = cifs_reconnect_tcon(tcon, smb_command);
Steve French790fe572007-07-07 19:25:05 +0000242 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243 return rc;
244
245 *request_buf = cifs_small_buf_get();
246 if (*request_buf == NULL) {
247 /* BB should we add a retry in here if not a writepage? */
248 return -ENOMEM;
249 }
250
Steve French63135e02007-07-17 17:34:02 +0000251 header_assemble((struct smb_hdr *) *request_buf, smb_command,
Steve Frenchc18c8422007-07-18 23:21:09 +0000252 tcon, wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253
Steve French790fe572007-07-07 19:25:05 +0000254 if (tcon != NULL)
255 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700256
Jeff Laytonf5695992010-09-29 15:27:08 -0400257 return 0;
Steve French5815449d2006-02-14 01:36:20 +0000258}
259
Steve French12b3b8f2006-02-09 21:12:47 +0000260int
Steve French50c2f752007-07-13 00:33:32 +0000261small_smb_init_no_tc(const int smb_command, const int wct,
Steve French96daf2b2011-05-27 04:34:02 +0000262 struct cifs_ses *ses, void **request_buf)
Steve French12b3b8f2006-02-09 21:12:47 +0000263{
264 int rc;
Steve French50c2f752007-07-13 00:33:32 +0000265 struct smb_hdr *buffer;
Steve French12b3b8f2006-02-09 21:12:47 +0000266
Steve French5815449d2006-02-14 01:36:20 +0000267 rc = small_smb_init(smb_command, wct, NULL, request_buf);
Steve French790fe572007-07-07 19:25:05 +0000268 if (rc)
Steve French12b3b8f2006-02-09 21:12:47 +0000269 return rc;
270
Steve French04fdabe2006-02-10 05:52:50 +0000271 buffer = (struct smb_hdr *)*request_buf;
Steve French12b3b8f2006-02-09 21:12:47 +0000272 buffer->Mid = GetNextMid(ses->server);
273 if (ses->capabilities & CAP_UNICODE)
274 buffer->Flags2 |= SMBFLG2_UNICODE;
Steve French04fdabe2006-02-10 05:52:50 +0000275 if (ses->capabilities & CAP_STATUS32)
Steve French12b3b8f2006-02-09 21:12:47 +0000276 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
277
278 /* uid, tid can stay at zero as set in header assemble */
279
Steve French50c2f752007-07-13 00:33:32 +0000280 /* BB add support for turning on the signing when
Steve French12b3b8f2006-02-09 21:12:47 +0000281 this function is used after 1st of session setup requests */
282
283 return rc;
284}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285
286/* If the return code is zero, this function must fill in request_buf pointer */
287static int
Steve French96daf2b2011-05-27 04:34:02 +0000288__smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400289 void **request_buf, void **response_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 *request_buf = cifs_buf_get();
292 if (*request_buf == NULL) {
293 /* BB should we add a retry in here if not a writepage? */
294 return -ENOMEM;
295 }
296 /* Although the original thought was we needed the response buf for */
297 /* potential retries of smb operations it turns out we can determine */
298 /* from the mid flags when the request buffer can be resent without */
299 /* having to use a second distinct buffer for the response */
Steve French790fe572007-07-07 19:25:05 +0000300 if (response_buf)
Steve French50c2f752007-07-13 00:33:32 +0000301 *response_buf = *request_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302
303 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000304 wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305
Steve French790fe572007-07-07 19:25:05 +0000306 if (tcon != NULL)
307 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700308
Jeff Laytonf5695992010-09-29 15:27:08 -0400309 return 0;
310}
311
312/* If the return code is zero, this function must fill in request_buf pointer */
313static int
Steve French96daf2b2011-05-27 04:34:02 +0000314smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400315 void **request_buf, void **response_buf)
316{
317 int rc;
318
319 rc = cifs_reconnect_tcon(tcon, smb_command);
320 if (rc)
321 return rc;
322
323 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
324}
325
326static int
Steve French96daf2b2011-05-27 04:34:02 +0000327smb_init_no_reconnect(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400328 void **request_buf, void **response_buf)
329{
330 if (tcon->ses->need_reconnect || tcon->need_reconnect)
331 return -EHOSTDOWN;
332
333 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334}
335
Steve French50c2f752007-07-13 00:33:32 +0000336static int validate_t2(struct smb_t2_rsp *pSMB)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337{
Jeff Layton12df83c2011-01-20 13:36:51 -0500338 unsigned int total_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339
Jeff Layton12df83c2011-01-20 13:36:51 -0500340 /* check for plausible wct */
341 if (pSMB->hdr.WordCount < 10)
342 goto vt2_err;
343
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344 /* check for parm and data offset going beyond end of smb */
Jeff Layton12df83c2011-01-20 13:36:51 -0500345 if (get_unaligned_le16(&pSMB->t2_rsp.ParameterOffset) > 1024 ||
346 get_unaligned_le16(&pSMB->t2_rsp.DataOffset) > 1024)
347 goto vt2_err;
348
Jeff Layton12df83c2011-01-20 13:36:51 -0500349 total_size = get_unaligned_le16(&pSMB->t2_rsp.ParameterCount);
350 if (total_size >= 512)
351 goto vt2_err;
352
Jeff Laytonfd5707e2011-03-31 17:22:07 -0400353 /* check that bcc is at least as big as parms + data, and that it is
354 * less than negotiated smb buffer
355 */
Jeff Layton12df83c2011-01-20 13:36:51 -0500356 total_size += get_unaligned_le16(&pSMB->t2_rsp.DataCount);
357 if (total_size > get_bcc(&pSMB->hdr) ||
358 total_size >= CIFSMaxBufSize + MAX_CIFS_HDR_SIZE)
359 goto vt2_err;
360
361 return 0;
362vt2_err:
Steve French50c2f752007-07-13 00:33:32 +0000363 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364 sizeof(struct smb_t2_rsp) + 16);
Jeff Layton12df83c2011-01-20 13:36:51 -0500365 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366}
Jeff Layton690c5222011-01-20 13:36:51 -0500367
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000368static inline void inc_rfc1001_len(void *pSMB, int count)
369{
370 struct smb_hdr *hdr = (struct smb_hdr *)pSMB;
371
372 be32_add_cpu(&hdr->smb_buf_length, count);
373}
374
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375int
Steve French96daf2b2011-05-27 04:34:02 +0000376CIFSSMBNegotiate(unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377{
378 NEGOTIATE_REQ *pSMB;
379 NEGOTIATE_RSP *pSMBr;
380 int rc = 0;
381 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000382 int i;
Steve French50c2f752007-07-13 00:33:32 +0000383 struct TCP_Server_Info *server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 u16 count;
Steve French750d1152006-06-27 06:28:30 +0000385 unsigned int secFlags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386
Steve French790fe572007-07-07 19:25:05 +0000387 if (ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 server = ses->server;
389 else {
390 rc = -EIO;
391 return rc;
392 }
393 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
394 (void **) &pSMB, (void **) &pSMBr);
395 if (rc)
396 return rc;
Steve French750d1152006-06-27 06:28:30 +0000397
398 /* if any of auth flags (ie not sign or seal) are overriden use them */
Steve French790fe572007-07-07 19:25:05 +0000399 if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
Steve French762e5ab2007-06-28 18:41:42 +0000400 secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
Steve French750d1152006-06-27 06:28:30 +0000401 else /* if override flags set only sign/seal OR them with global auth */
Jeff Layton04912d62010-04-24 07:57:45 -0400402 secFlags = global_secflags | ses->overrideSecFlg;
Steve French750d1152006-06-27 06:28:30 +0000403
Joe Perchesb6b38f72010-04-21 03:50:45 +0000404 cFYI(1, "secFlags 0x%x", secFlags);
Steve Frenchf40c5622006-06-28 00:13:38 +0000405
Steve French1982c342005-08-17 12:38:22 -0700406 pSMB->hdr.Mid = GetNextMid(server);
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000407 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
Steve Frencha0136892007-10-04 20:05:09 +0000408
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000409 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
Steve French254e55e2006-06-04 05:53:15 +0000410 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Steve Frencha0136892007-10-04 20:05:09 +0000411 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000412 cFYI(1, "Kerberos only mechanism, enable extended security");
Steve Frencha0136892007-10-04 20:05:09 +0000413 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Jeff Laytonb4d6fcf2011-01-07 11:30:28 -0500414 } else if ((secFlags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP)
Steve Frenchac683922009-05-06 04:16:04 +0000415 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
416 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_NTLMSSP) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000417 cFYI(1, "NTLMSSP only mechanism, enable extended security");
Steve Frenchac683922009-05-06 04:16:04 +0000418 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
419 }
Steve French50c2f752007-07-13 00:33:32 +0000420
Steve French39798772006-05-31 22:40:51 +0000421 count = 0;
Steve French50c2f752007-07-13 00:33:32 +0000422 for (i = 0; i < CIFS_NUM_PROT; i++) {
Steve French39798772006-05-31 22:40:51 +0000423 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
424 count += strlen(protocols[i].name) + 1;
425 /* null at end of source and target buffers anyway */
426 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000427 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428 pSMB->ByteCount = cpu_to_le16(count);
429
430 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
431 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French50c2f752007-07-13 00:33:32 +0000432 if (rc != 0)
Steve French254e55e2006-06-04 05:53:15 +0000433 goto neg_err_exit;
434
Jeff Layton9bf67e52010-04-24 07:57:46 -0400435 server->dialect = le16_to_cpu(pSMBr->DialectIndex);
436 cFYI(1, "Dialect: %d", server->dialect);
Steve French254e55e2006-06-04 05:53:15 +0000437 /* Check wct = 1 error case */
Jeff Layton9bf67e52010-04-24 07:57:46 -0400438 if ((pSMBr->hdr.WordCount < 13) || (server->dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000439 /* core returns wct = 1, but we do not ask for core - otherwise
Steve French50c2f752007-07-13 00:33:32 +0000440 small wct just comes when dialect index is -1 indicating we
Steve French254e55e2006-06-04 05:53:15 +0000441 could not negotiate a common dialect */
442 rc = -EOPNOTSUPP;
443 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000444#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French790fe572007-07-07 19:25:05 +0000445 } else if ((pSMBr->hdr.WordCount == 13)
Jeff Layton9bf67e52010-04-24 07:57:46 -0400446 && ((server->dialect == LANMAN_PROT)
447 || (server->dialect == LANMAN2_PROT))) {
Steve Frenchb815f1e52006-10-02 05:53:29 +0000448 __s16 tmp;
Steve French50c2f752007-07-13 00:33:32 +0000449 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
Steve French254e55e2006-06-04 05:53:15 +0000450
Steve French790fe572007-07-07 19:25:05 +0000451 if ((secFlags & CIFSSEC_MAY_LANMAN) ||
Steve French750d1152006-06-27 06:28:30 +0000452 (secFlags & CIFSSEC_MAY_PLNTXT))
Steve French254e55e2006-06-04 05:53:15 +0000453 server->secType = LANMAN;
454 else {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000455 cERROR(1, "mount failed weak security disabled"
456 " in /proc/fs/cifs/SecurityFlags");
Steve French39798772006-05-31 22:40:51 +0000457 rc = -EOPNOTSUPP;
458 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000459 }
Steve French96daf2b2011-05-27 04:34:02 +0000460 server->sec_mode = (__u8)le16_to_cpu(rsp->SecurityMode);
Pavel Shilovsky10b9b982012-03-20 12:55:09 +0300461 server->maxReq = min_t(unsigned int,
462 le16_to_cpu(rsp->MaxMpxCount),
463 cifs_max_pending);
464 server->oplocks = server->maxReq > 1 ? enable_oplocks : false;
Jeff Laytonc974bef2011-10-11 06:41:32 -0400465 server->maxBuf = le16_to_cpu(rsp->MaxBufSize);
Steve Frencheca6acf2009-02-20 05:43:09 +0000466 server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
Steve French254e55e2006-06-04 05:53:15 +0000467 /* even though we do not use raw we might as well set this
468 accurately, in case we ever find a need for it */
Steve French790fe572007-07-07 19:25:05 +0000469 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
Steve Frencheca6acf2009-02-20 05:43:09 +0000470 server->max_rw = 0xFF00;
Steve French254e55e2006-06-04 05:53:15 +0000471 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
472 } else {
Steve Frencheca6acf2009-02-20 05:43:09 +0000473 server->max_rw = 0;/* do not need to use raw anyway */
Steve French254e55e2006-06-04 05:53:15 +0000474 server->capabilities = CAP_MPX_MODE;
475 }
Steve Frenchb815f1e52006-10-02 05:53:29 +0000476 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
Steve French1a70d652006-10-02 05:59:18 +0000477 if (tmp == -1) {
Steve French25ee4a92006-09-30 00:54:23 +0000478 /* OS/2 often does not set timezone therefore
479 * we must use server time to calc time zone.
Steve Frenchb815f1e52006-10-02 05:53:29 +0000480 * Could deviate slightly from the right zone.
481 * Smallest defined timezone difference is 15 minutes
482 * (i.e. Nepal). Rounding up/down is done to match
483 * this requirement.
Steve French25ee4a92006-09-30 00:54:23 +0000484 */
Steve Frenchb815f1e52006-10-02 05:53:29 +0000485 int val, seconds, remain, result;
Steve French25ee4a92006-09-30 00:54:23 +0000486 struct timespec ts, utc;
487 utc = CURRENT_TIME;
Jeff Laytonc4a2c082009-05-27 09:37:33 -0400488 ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
489 rsp->SrvTime.Time, 0);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000490 cFYI(1, "SrvTime %d sec since 1970 (utc: %d) diff: %d",
Steve French50c2f752007-07-13 00:33:32 +0000491 (int)ts.tv_sec, (int)utc.tv_sec,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000492 (int)(utc.tv_sec - ts.tv_sec));
Steve Frenchb815f1e52006-10-02 05:53:29 +0000493 val = (int)(utc.tv_sec - ts.tv_sec);
Andre Haupt8594c152007-08-30 20:18:41 +0000494 seconds = abs(val);
Steve French947a5062006-10-02 05:55:25 +0000495 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
Steve Frenchb815f1e52006-10-02 05:53:29 +0000496 remain = seconds % MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000497 if (remain >= (MIN_TZ_ADJ / 2))
Steve Frenchb815f1e52006-10-02 05:53:29 +0000498 result += MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000499 if (val < 0)
Steve Frenchad7a2922008-02-07 23:25:02 +0000500 result = -result;
Steve Frenchb815f1e52006-10-02 05:53:29 +0000501 server->timeAdj = result;
Steve French25ee4a92006-09-30 00:54:23 +0000502 } else {
Steve Frenchb815f1e52006-10-02 05:53:29 +0000503 server->timeAdj = (int)tmp;
504 server->timeAdj *= 60; /* also in seconds */
Steve French25ee4a92006-09-30 00:54:23 +0000505 }
Joe Perchesb6b38f72010-04-21 03:50:45 +0000506 cFYI(1, "server->timeAdj: %d seconds", server->timeAdj);
Steve French25ee4a92006-09-30 00:54:23 +0000507
Steve French39798772006-05-31 22:40:51 +0000508
Steve French254e55e2006-06-04 05:53:15 +0000509 /* BB get server time for time conversions and add
Steve French50c2f752007-07-13 00:33:32 +0000510 code to use it and timezone since this is not UTC */
Steve French39798772006-05-31 22:40:51 +0000511
Steve French50c2f752007-07-13 00:33:32 +0000512 if (rsp->EncryptionKeyLength ==
Steve French25ee4a92006-09-30 00:54:23 +0000513 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500514 memcpy(ses->server->cryptkey, rsp->EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000515 CIFS_CRYPTO_KEY_SIZE);
Steve French96daf2b2011-05-27 04:34:02 +0000516 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
Steve French254e55e2006-06-04 05:53:15 +0000517 rc = -EIO; /* need cryptkey unless plain text */
518 goto neg_err_exit;
519 }
Steve French39798772006-05-31 22:40:51 +0000520
Steve Frenchf19159d2010-04-21 04:12:10 +0000521 cFYI(1, "LANMAN negotiated");
Steve French254e55e2006-06-04 05:53:15 +0000522 /* we will not end up setting signing flags - as no signing
523 was in LANMAN and server did not return the flags on */
524 goto signing_check;
Steve French7c7b25b2006-06-01 19:20:10 +0000525#else /* weak security disabled */
Steve French790fe572007-07-07 19:25:05 +0000526 } else if (pSMBr->hdr.WordCount == 13) {
Steve Frenchf19159d2010-04-21 04:12:10 +0000527 cERROR(1, "mount failed, cifs module not built "
528 "with CIFS_WEAK_PW_HASH support");
Dan Carpenter8212cf72010-03-15 11:22:26 +0300529 rc = -EOPNOTSUPP;
Steve French7c7b25b2006-06-01 19:20:10 +0000530#endif /* WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000531 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000532 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000533 /* unknown wct */
534 rc = -EOPNOTSUPP;
535 goto neg_err_exit;
536 }
537 /* else wct == 17 NTLM */
Steve French96daf2b2011-05-27 04:34:02 +0000538 server->sec_mode = pSMBr->SecurityMode;
539 if ((server->sec_mode & SECMODE_USER) == 0)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000540 cFYI(1, "share mode security");
Steve French39798772006-05-31 22:40:51 +0000541
Steve French96daf2b2011-05-27 04:34:02 +0000542 if ((server->sec_mode & SECMODE_PW_ENCRYPT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000543#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French750d1152006-06-27 06:28:30 +0000544 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000545#endif /* CIFS_WEAK_PW_HASH */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000546 cERROR(1, "Server requests plain text password"
547 " but client support disabled");
Steve French9312f672006-06-04 22:21:07 +0000548
Steve French790fe572007-07-07 19:25:05 +0000549 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
Steve French254e55e2006-06-04 05:53:15 +0000550 server->secType = NTLMv2;
Steve French790fe572007-07-07 19:25:05 +0000551 else if (secFlags & CIFSSEC_MAY_NTLM)
Steve French254e55e2006-06-04 05:53:15 +0000552 server->secType = NTLM;
Steve French790fe572007-07-07 19:25:05 +0000553 else if (secFlags & CIFSSEC_MAY_NTLMV2)
Steve Frenchf40c5622006-06-28 00:13:38 +0000554 server->secType = NTLMv2;
Steve Frencha0136892007-10-04 20:05:09 +0000555 else if (secFlags & CIFSSEC_MAY_KRB5)
556 server->secType = Kerberos;
Steve Frenchac683922009-05-06 04:16:04 +0000557 else if (secFlags & CIFSSEC_MAY_NTLMSSP)
Steve Frenchf46c7232009-06-25 03:04:20 +0000558 server->secType = RawNTLMSSP;
Steve Frencha0136892007-10-04 20:05:09 +0000559 else if (secFlags & CIFSSEC_MAY_LANMAN)
560 server->secType = LANMAN;
Steve Frencha0136892007-10-04 20:05:09 +0000561 else {
562 rc = -EOPNOTSUPP;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000563 cERROR(1, "Invalid security type");
Steve Frencha0136892007-10-04 20:05:09 +0000564 goto neg_err_exit;
565 }
566 /* else ... any others ...? */
Steve French7c7b25b2006-06-01 19:20:10 +0000567
Steve French254e55e2006-06-04 05:53:15 +0000568 /* one byte, so no need to convert this or EncryptionKeyLen from
569 little endian */
Pavel Shilovsky10b9b982012-03-20 12:55:09 +0300570 server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount),
571 cifs_max_pending);
572 server->oplocks = server->maxReq > 1 ? enable_oplocks : false;
Steve French254e55e2006-06-04 05:53:15 +0000573 /* probably no need to store and check maxvcs */
Jeff Laytonc974bef2011-10-11 06:41:32 -0400574 server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize);
Steve Frencheca6acf2009-02-20 05:43:09 +0000575 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000576 cFYI(DBG2, "Max buf = %d", ses->server->maxBuf);
Steve French254e55e2006-06-04 05:53:15 +0000577 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e52006-10-02 05:53:29 +0000578 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
579 server->timeAdj *= 60;
Steve French254e55e2006-06-04 05:53:15 +0000580 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500581 memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000582 CIFS_CRYPTO_KEY_SIZE);
Steve French07cc6cf2011-05-27 04:12:29 +0000583 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC ||
584 server->capabilities & CAP_EXTENDED_SECURITY) &&
585 (pSMBr->EncryptionKeyLength == 0)) {
Steve French254e55e2006-06-04 05:53:15 +0000586 /* decode security blob */
Jeff Layton820a8032011-05-04 08:05:26 -0400587 count = get_bcc(&pSMBr->hdr);
Jeff Laytone187e442007-10-16 17:10:44 +0000588 if (count < 16) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589 rc = -EIO;
Jeff Laytone187e442007-10-16 17:10:44 +0000590 goto neg_err_exit;
591 }
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530592 spin_lock(&cifs_tcp_ses_lock);
Jeff Laytone7ddee92008-11-14 13:44:38 -0500593 if (server->srv_count > 1) {
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530594 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000595 if (memcmp(server->server_GUID,
596 pSMBr->u.extended_response.
597 GUID, 16) != 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000598 cFYI(1, "server UID changed");
Steve French254e55e2006-06-04 05:53:15 +0000599 memcpy(server->server_GUID,
Jeff Laytone187e442007-10-16 17:10:44 +0000600 pSMBr->u.extended_response.GUID,
601 16);
602 }
Jeff Laytone7ddee92008-11-14 13:44:38 -0500603 } else {
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530604 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000605 memcpy(server->server_GUID,
606 pSMBr->u.extended_response.GUID, 16);
Jeff Laytone7ddee92008-11-14 13:44:38 -0500607 }
Jeff Laytone187e442007-10-16 17:10:44 +0000608
609 if (count == 16) {
610 server->secType = RawNTLMSSP;
Steve French254e55e2006-06-04 05:53:15 +0000611 } else {
612 rc = decode_negTokenInit(pSMBr->u.extended_response.
Jeff Layton26efa0b2010-04-24 07:57:49 -0400613 SecurityBlob, count - 16,
614 server);
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000615 if (rc == 1)
Jeff Laytone5459372007-11-03 05:11:06 +0000616 rc = 0;
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000617 else
Steve French254e55e2006-06-04 05:53:15 +0000618 rc = -EINVAL;
Shirish Pargaonkar2b149f12010-09-18 22:02:18 -0500619 if (server->secType == Kerberos) {
620 if (!server->sec_kerberos &&
621 !server->sec_mskerberos)
622 rc = -EOPNOTSUPP;
623 } else if (server->secType == RawNTLMSSP) {
624 if (!server->sec_ntlmssp)
625 rc = -EOPNOTSUPP;
626 } else
627 rc = -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628 }
Steve French96daf2b2011-05-27 04:34:02 +0000629 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
Steve French07cc6cf2011-05-27 04:12:29 +0000630 rc = -EIO; /* no crypt key only if plain text pwd */
631 goto neg_err_exit;
Steve French254e55e2006-06-04 05:53:15 +0000632 } else
633 server->capabilities &= ~CAP_EXTENDED_SECURITY;
634
Steve French6344a422006-06-12 04:18:35 +0000635#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French254e55e2006-06-04 05:53:15 +0000636signing_check:
Steve French6344a422006-06-12 04:18:35 +0000637#endif
Steve French762e5ab2007-06-28 18:41:42 +0000638 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
639 /* MUST_SIGN already includes the MAY_SIGN FLAG
640 so if this is zero it means that signing is disabled */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000641 cFYI(1, "Signing disabled");
Steve French96daf2b2011-05-27 04:34:02 +0000642 if (server->sec_mode & SECMODE_SIGN_REQUIRED) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000643 cERROR(1, "Server requires "
Jeff Layton7111d212007-10-16 16:50:25 +0000644 "packet signing to be enabled in "
Joe Perchesb6b38f72010-04-21 03:50:45 +0000645 "/proc/fs/cifs/SecurityFlags.");
Steve Frenchabb63d62007-10-18 02:58:40 +0000646 rc = -EOPNOTSUPP;
647 }
Steve French96daf2b2011-05-27 04:34:02 +0000648 server->sec_mode &=
Steve French254e55e2006-06-04 05:53:15 +0000649 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Steve French762e5ab2007-06-28 18:41:42 +0000650 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
651 /* signing required */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000652 cFYI(1, "Must sign - secFlags 0x%x", secFlags);
Steve French96daf2b2011-05-27 04:34:02 +0000653 if ((server->sec_mode &
Steve French762e5ab2007-06-28 18:41:42 +0000654 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000655 cERROR(1, "signing required but server lacks support");
Jeff38c10a12007-07-06 21:10:07 +0000656 rc = -EOPNOTSUPP;
Steve French762e5ab2007-06-28 18:41:42 +0000657 } else
Steve French96daf2b2011-05-27 04:34:02 +0000658 server->sec_mode |= SECMODE_SIGN_REQUIRED;
Steve French762e5ab2007-06-28 18:41:42 +0000659 } else {
660 /* signing optional ie CIFSSEC_MAY_SIGN */
Steve French96daf2b2011-05-27 04:34:02 +0000661 if ((server->sec_mode & SECMODE_SIGN_REQUIRED) == 0)
662 server->sec_mode &=
Steve French254e55e2006-06-04 05:53:15 +0000663 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 }
Steve French50c2f752007-07-13 00:33:32 +0000665
666neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700667 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000668
Joe Perchesb6b38f72010-04-21 03:50:45 +0000669 cFYI(1, "negprot rc %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 return rc;
671}
672
673int
Steve French96daf2b2011-05-27 04:34:02 +0000674CIFSSMBTDis(const int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675{
676 struct smb_hdr *smb_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678
Joe Perchesb6b38f72010-04-21 03:50:45 +0000679 cFYI(1, "In tree disconnect");
Jeff Laytonf1987b42008-11-15 11:12:47 -0500680
681 /* BB: do we need to check this? These should never be NULL. */
682 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
683 return -EIO;
684
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 /*
Jeff Laytonf1987b42008-11-15 11:12:47 -0500686 * No need to return error on this operation if tid invalidated and
687 * closed on server already e.g. due to tcp session crashing. Also,
688 * the tcon is no longer on the list, so no need to take lock before
689 * checking this.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 */
Steve French268875b2009-06-25 00:29:21 +0000691 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
Steve French50c2f752007-07-13 00:33:32 +0000692 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693
Steve French50c2f752007-07-13 00:33:32 +0000694 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700695 (void **)&smb_buffer);
Jeff Laytonf1987b42008-11-15 11:12:47 -0500696 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 return rc;
Steve French133672e2007-11-13 22:41:37 +0000698
699 rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000701 cFYI(1, "Tree disconnect failed %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702
Steve French50c2f752007-07-13 00:33:32 +0000703 /* No need to return error on this operation if tid invalidated and
Jeff Laytonf1987b42008-11-15 11:12:47 -0500704 closed on server already e.g. due to tcp session crashing */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 if (rc == -EAGAIN)
706 rc = 0;
707
708 return rc;
709}
710
Jeff Layton766fdbb2011-01-11 07:24:21 -0500711/*
712 * This is a no-op for now. We're not really interested in the reply, but
713 * rather in the fact that the server sent one and that server->lstrp
714 * gets updated.
715 *
716 * FIXME: maybe we should consider checking that the reply matches request?
717 */
718static void
719cifs_echo_callback(struct mid_q_entry *mid)
720{
721 struct TCP_Server_Info *server = mid->callback_data;
722
723 DeleteMidQEntry(mid);
724 atomic_dec(&server->inFlight);
725 wake_up(&server->request_q);
726}
727
728int
729CIFSSMBEcho(struct TCP_Server_Info *server)
730{
731 ECHO_REQ *smb;
732 int rc = 0;
Jeff Laytonfcc31cb2011-05-19 16:22:53 -0400733 struct kvec iov;
Jeff Layton766fdbb2011-01-11 07:24:21 -0500734
735 cFYI(1, "In echo request");
736
737 rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
738 if (rc)
739 return rc;
740
741 /* set up echo request */
Steve French5443d132011-03-13 05:08:25 +0000742 smb->hdr.Tid = 0xffff;
Jeff Layton99d86c8f2011-01-20 21:19:25 -0500743 smb->hdr.WordCount = 1;
744 put_unaligned_le16(1, &smb->EchoCount);
Jeff Layton820a8032011-05-04 08:05:26 -0400745 put_bcc(1, &smb->hdr);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500746 smb->Data[0] = 'a';
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000747 inc_rfc1001_len(smb, 3);
Jeff Laytonfcc31cb2011-05-19 16:22:53 -0400748 iov.iov_base = smb;
749 iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
Jeff Layton766fdbb2011-01-11 07:24:21 -0500750
Jeff Layton44d22d82011-10-19 15:29:49 -0400751 rc = cifs_call_async(server, &iov, 1, NULL, cifs_echo_callback,
752 server, true);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500753 if (rc)
754 cFYI(1, "Echo request failed: %d", rc);
755
756 cifs_small_buf_release(smb);
757
758 return rc;
759}
760
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761int
Steve French96daf2b2011-05-27 04:34:02 +0000762CIFSSMBLogoff(const int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 LOGOFF_ANDX_REQ *pSMB;
765 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766
Joe Perchesb6b38f72010-04-21 03:50:45 +0000767 cFYI(1, "In SMBLogoff for session disconnect");
Jeff Layton14fbf502008-11-14 13:53:46 -0500768
769 /*
770 * BB: do we need to check validity of ses and server? They should
771 * always be valid since we have an active reference. If not, that
772 * should probably be a BUG()
773 */
774 if (!ses || !ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 return -EIO;
776
Steve Frenchd7b619c2010-02-25 05:36:46 +0000777 mutex_lock(&ses->session_mutex);
Steve French3b795212008-11-13 19:45:32 +0000778 if (ses->need_reconnect)
779 goto session_already_dead; /* no need to send SMBlogoff if uid
780 already closed due to reconnect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
782 if (rc) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000783 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 return rc;
785 }
786
Steve French3b795212008-11-13 19:45:32 +0000787 pSMB->hdr.Mid = GetNextMid(ses->server);
Steve French1982c342005-08-17 12:38:22 -0700788
Steve French96daf2b2011-05-27 04:34:02 +0000789 if (ses->server->sec_mode &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
791 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792
793 pSMB->hdr.Uid = ses->Suid;
794
795 pSMB->AndXCommand = 0xFF;
Steve French133672e2007-11-13 22:41:37 +0000796 rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
Steve French3b795212008-11-13 19:45:32 +0000797session_already_dead:
Steve Frenchd7b619c2010-02-25 05:36:46 +0000798 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799
800 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000801 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802 error */
803 if (rc == -EAGAIN)
804 rc = 0;
805 return rc;
806}
807
808int
Steve French96daf2b2011-05-27 04:34:02 +0000809CIFSPOSIXDelFile(const int xid, struct cifs_tcon *tcon, const char *fileName,
Steve French2d785a52007-07-15 01:48:57 +0000810 __u16 type, const struct nls_table *nls_codepage, int remap)
811{
812 TRANSACTION2_SPI_REQ *pSMB = NULL;
813 TRANSACTION2_SPI_RSP *pSMBr = NULL;
814 struct unlink_psx_rq *pRqD;
815 int name_len;
816 int rc = 0;
817 int bytes_returned = 0;
818 __u16 params, param_offset, offset, byte_count;
819
Joe Perchesb6b38f72010-04-21 03:50:45 +0000820 cFYI(1, "In POSIX delete");
Steve French2d785a52007-07-15 01:48:57 +0000821PsxDelete:
822 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
823 (void **) &pSMBr);
824 if (rc)
825 return rc;
826
827 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
828 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -0600829 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
830 PATH_MAX, nls_codepage, remap);
Steve French2d785a52007-07-15 01:48:57 +0000831 name_len++; /* trailing null */
832 name_len *= 2;
833 } else { /* BB add path length overrun check */
834 name_len = strnlen(fileName, PATH_MAX);
835 name_len++; /* trailing null */
836 strncpy(pSMB->FileName, fileName, name_len);
837 }
838
839 params = 6 + name_len;
840 pSMB->MaxParameterCount = cpu_to_le16(2);
841 pSMB->MaxDataCount = 0; /* BB double check this with jra */
842 pSMB->MaxSetupCount = 0;
843 pSMB->Reserved = 0;
844 pSMB->Flags = 0;
845 pSMB->Timeout = 0;
846 pSMB->Reserved2 = 0;
847 param_offset = offsetof(struct smb_com_transaction2_spi_req,
848 InformationLevel) - 4;
849 offset = param_offset + params;
850
851 /* Setup pointer to Request Data (inode type) */
852 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
853 pRqD->type = cpu_to_le16(type);
854 pSMB->ParameterOffset = cpu_to_le16(param_offset);
855 pSMB->DataOffset = cpu_to_le16(offset);
856 pSMB->SetupCount = 1;
857 pSMB->Reserved3 = 0;
858 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
859 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
860
861 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
862 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
863 pSMB->ParameterCount = cpu_to_le16(params);
864 pSMB->TotalParameterCount = pSMB->ParameterCount;
865 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
866 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000867 inc_rfc1001_len(pSMB, byte_count);
Steve French2d785a52007-07-15 01:48:57 +0000868 pSMB->ByteCount = cpu_to_le16(byte_count);
869 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
870 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000871 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000872 cFYI(1, "Posix delete returned %d", rc);
Steve French2d785a52007-07-15 01:48:57 +0000873 cifs_buf_release(pSMB);
874
875 cifs_stats_inc(&tcon->num_deletes);
876
877 if (rc == -EAGAIN)
878 goto PsxDelete;
879
880 return rc;
881}
882
883int
Steve French96daf2b2011-05-27 04:34:02 +0000884CIFSSMBDelFile(const int xid, struct cifs_tcon *tcon, const char *fileName,
Steve French737b7582005-04-28 22:41:06 -0700885 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886{
887 DELETE_FILE_REQ *pSMB = NULL;
888 DELETE_FILE_RSP *pSMBr = NULL;
889 int rc = 0;
890 int bytes_returned;
891 int name_len;
892
893DelFileRetry:
894 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
895 (void **) &pSMBr);
896 if (rc)
897 return rc;
898
899 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
900 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -0600901 cifsConvertToUTF16((__le16 *) pSMB->fileName, fileName,
902 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 name_len++; /* trailing null */
904 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700905 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 name_len = strnlen(fileName, PATH_MAX);
907 name_len++; /* trailing null */
908 strncpy(pSMB->fileName, fileName, name_len);
909 }
910 pSMB->SearchAttributes =
911 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
912 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000913 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 pSMB->ByteCount = cpu_to_le16(name_len + 1);
915 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
916 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700917 cifs_stats_inc(&tcon->num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000918 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000919 cFYI(1, "Error in RMFile = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920
921 cifs_buf_release(pSMB);
922 if (rc == -EAGAIN)
923 goto DelFileRetry;
924
925 return rc;
926}
927
928int
Steve French96daf2b2011-05-27 04:34:02 +0000929CIFSSMBRmDir(const int xid, struct cifs_tcon *tcon, const char *dirName,
Steve French737b7582005-04-28 22:41:06 -0700930 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931{
932 DELETE_DIRECTORY_REQ *pSMB = NULL;
933 DELETE_DIRECTORY_RSP *pSMBr = NULL;
934 int rc = 0;
935 int bytes_returned;
936 int name_len;
937
Joe Perchesb6b38f72010-04-21 03:50:45 +0000938 cFYI(1, "In CIFSSMBRmDir");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939RmDirRetry:
940 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
941 (void **) &pSMBr);
942 if (rc)
943 return rc;
944
945 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -0600946 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, dirName,
947 PATH_MAX, nls_codepage, 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 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951 name_len = strnlen(dirName, PATH_MAX);
952 name_len++; /* trailing null */
953 strncpy(pSMB->DirName, dirName, name_len);
954 }
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);
Steve Frencha4544342005-08-24 13:59:35 -0700961 cifs_stats_inc(&tcon->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
Steve French96daf2b2011-05-27 04:34:02 +0000972CIFSSMBMkDir(const int xid, struct cifs_tcon *tcon,
Steve French737b7582005-04-28 22:41:06 -0700973 const char *name, const struct nls_table *nls_codepage, int remap)
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;
980
Joe Perchesb6b38f72010-04-21 03:50:45 +0000981 cFYI(1, "In CIFSSMBMkDir");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982MkDirRetry:
983 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
984 (void **) &pSMBr);
985 if (rc)
986 return rc;
987
988 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -0600989 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
990 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991 name_len++; /* trailing null */
992 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700993 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 name_len = strnlen(name, PATH_MAX);
995 name_len++; /* trailing null */
996 strncpy(pSMB->DirName, name, name_len);
997 }
998
999 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001000 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001 pSMB->ByteCount = cpu_to_le16(name_len + 1);
1002 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1003 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001004 cifs_stats_inc(&tcon->num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +00001005 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001006 cFYI(1, "Error in Mkdir = %d", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07001007
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 cifs_buf_release(pSMB);
1009 if (rc == -EAGAIN)
1010 goto MkDirRetry;
1011 return rc;
1012}
1013
Steve French2dd29d32007-04-23 22:07:35 +00001014int
Steve French96daf2b2011-05-27 04:34:02 +00001015CIFSPOSIXCreate(const int xid, struct cifs_tcon *tcon, __u32 posix_flags,
Steve Frenchad7a2922008-02-07 23:25:02 +00001016 __u64 mode, __u16 *netfid, FILE_UNIX_BASIC_INFO *pRetData,
Steve French50c2f752007-07-13 00:33:32 +00001017 __u32 *pOplock, const char *name,
Steve French2dd29d32007-04-23 22:07:35 +00001018 const struct nls_table *nls_codepage, int remap)
1019{
1020 TRANSACTION2_SPI_REQ *pSMB = NULL;
1021 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1022 int name_len;
1023 int rc = 0;
1024 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001025 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +00001026 OPEN_PSX_REQ *pdata;
1027 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +00001028
Joe Perchesb6b38f72010-04-21 03:50:45 +00001029 cFYI(1, "In POSIX Create");
Steve French2dd29d32007-04-23 22:07:35 +00001030PsxCreat:
1031 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1032 (void **) &pSMBr);
1033 if (rc)
1034 return rc;
1035
1036 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1037 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001038 cifsConvertToUTF16((__le16 *) pSMB->FileName, name,
1039 PATH_MAX, nls_codepage, remap);
Steve French2dd29d32007-04-23 22:07:35 +00001040 name_len++; /* trailing null */
1041 name_len *= 2;
1042 } else { /* BB improve the check for buffer overruns BB */
1043 name_len = strnlen(name, PATH_MAX);
1044 name_len++; /* trailing null */
1045 strncpy(pSMB->FileName, name, name_len);
1046 }
1047
1048 params = 6 + name_len;
1049 count = sizeof(OPEN_PSX_REQ);
1050 pSMB->MaxParameterCount = cpu_to_le16(2);
1051 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1052 pSMB->MaxSetupCount = 0;
1053 pSMB->Reserved = 0;
1054 pSMB->Flags = 0;
1055 pSMB->Timeout = 0;
1056 pSMB->Reserved2 = 0;
1057 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001058 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001059 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001060 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001061 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001062 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001063 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001064 pdata->OpenFlags = cpu_to_le32(*pOplock);
1065 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1066 pSMB->DataOffset = cpu_to_le16(offset);
1067 pSMB->SetupCount = 1;
1068 pSMB->Reserved3 = 0;
1069 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1070 byte_count = 3 /* pad */ + params + count;
1071
1072 pSMB->DataCount = cpu_to_le16(count);
1073 pSMB->ParameterCount = cpu_to_le16(params);
1074 pSMB->TotalDataCount = pSMB->DataCount;
1075 pSMB->TotalParameterCount = pSMB->ParameterCount;
1076 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1077 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001078 inc_rfc1001_len(pSMB, byte_count);
Steve French2dd29d32007-04-23 22:07:35 +00001079 pSMB->ByteCount = cpu_to_le16(byte_count);
1080 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1081 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1082 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001083 cFYI(1, "Posix create returned %d", rc);
Steve French2dd29d32007-04-23 22:07:35 +00001084 goto psx_create_err;
1085 }
1086
Joe Perchesb6b38f72010-04-21 03:50:45 +00001087 cFYI(1, "copying inode info");
Steve French2dd29d32007-04-23 22:07:35 +00001088 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1089
Jeff Layton820a8032011-05-04 08:05:26 -04001090 if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) {
Steve French2dd29d32007-04-23 22:07:35 +00001091 rc = -EIO; /* bad smb */
1092 goto psx_create_err;
1093 }
1094
1095 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001096 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001097 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001098
Steve French2dd29d32007-04-23 22:07:35 +00001099 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001100 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001101 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1102 /* Let caller know file was created so we can set the mode. */
1103 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001104 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001105 *pOplock |= CIFS_CREATE_ACTION;
1106 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001107 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1108 pRetData->Type = cpu_to_le32(-1); /* unknown */
Joe Perchesb6b38f72010-04-21 03:50:45 +00001109 cFYI(DBG2, "unknown type");
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001110 } else {
Jeff Layton820a8032011-05-04 08:05:26 -04001111 if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001112 + sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001113 cERROR(1, "Open response data too small");
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001114 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001115 goto psx_create_err;
1116 }
Steve French50c2f752007-07-13 00:33:32 +00001117 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001118 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001119 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001120 }
Steve French2dd29d32007-04-23 22:07:35 +00001121
1122psx_create_err:
1123 cifs_buf_release(pSMB);
1124
Steve French65bc98b2009-07-10 15:27:25 +00001125 if (posix_flags & SMB_O_DIRECTORY)
1126 cifs_stats_inc(&tcon->num_posixmkdirs);
1127 else
1128 cifs_stats_inc(&tcon->num_posixopens);
Steve French2dd29d32007-04-23 22:07:35 +00001129
1130 if (rc == -EAGAIN)
1131 goto PsxCreat;
1132
Steve French50c2f752007-07-13 00:33:32 +00001133 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001134}
1135
Steve Frencha9d02ad2005-08-24 23:06:05 -07001136static __u16 convert_disposition(int disposition)
1137{
1138 __u16 ofun = 0;
1139
1140 switch (disposition) {
1141 case FILE_SUPERSEDE:
1142 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1143 break;
1144 case FILE_OPEN:
1145 ofun = SMBOPEN_OAPPEND;
1146 break;
1147 case FILE_CREATE:
1148 ofun = SMBOPEN_OCREATE;
1149 break;
1150 case FILE_OPEN_IF:
1151 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1152 break;
1153 case FILE_OVERWRITE:
1154 ofun = SMBOPEN_OTRUNC;
1155 break;
1156 case FILE_OVERWRITE_IF:
1157 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1158 break;
1159 default:
Joe Perchesb6b38f72010-04-21 03:50:45 +00001160 cFYI(1, "unknown disposition %d", disposition);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001161 ofun = SMBOPEN_OAPPEND; /* regular open */
1162 }
1163 return ofun;
1164}
1165
Jeff Layton35fc37d2008-05-14 10:22:03 -07001166static int
1167access_flags_to_smbopen_mode(const int access_flags)
1168{
1169 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1170
1171 if (masked_flags == GENERIC_READ)
1172 return SMBOPEN_READ;
1173 else if (masked_flags == GENERIC_WRITE)
1174 return SMBOPEN_WRITE;
1175
1176 /* just go for read/write */
1177 return SMBOPEN_READWRITE;
1178}
1179
Steve Frencha9d02ad2005-08-24 23:06:05 -07001180int
Steve French96daf2b2011-05-27 04:34:02 +00001181SMBLegacyOpen(const int xid, struct cifs_tcon *tcon,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001182 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001183 const int access_flags, const int create_options, __u16 *netfid,
1184 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001185 const struct nls_table *nls_codepage, int remap)
1186{
1187 int rc = -EACCES;
1188 OPENX_REQ *pSMB = NULL;
1189 OPENX_RSP *pSMBr = NULL;
1190 int bytes_returned;
1191 int name_len;
1192 __u16 count;
1193
1194OldOpenRetry:
1195 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1196 (void **) &pSMBr);
1197 if (rc)
1198 return rc;
1199
1200 pSMB->AndXCommand = 0xFF; /* none */
1201
1202 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1203 count = 1; /* account for one byte pad to word boundary */
1204 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001205 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1206 fileName, PATH_MAX, nls_codepage, remap);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001207 name_len++; /* trailing null */
1208 name_len *= 2;
1209 } else { /* BB improve check for buffer overruns BB */
1210 count = 0; /* no pad */
1211 name_len = strnlen(fileName, PATH_MAX);
1212 name_len++; /* trailing null */
1213 strncpy(pSMB->fileName, fileName, name_len);
1214 }
1215 if (*pOplock & REQ_OPLOCK)
1216 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001217 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001218 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001219
Steve Frencha9d02ad2005-08-24 23:06:05 -07001220 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001221 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001222 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1223 /* set file as system file if special file such
1224 as fifo and server expecting SFU style and
1225 no Unix extensions */
1226
Steve French790fe572007-07-07 19:25:05 +00001227 if (create_options & CREATE_OPTION_SPECIAL)
1228 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001229 else /* BB FIXME BB */
1230 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001231
Jeff Layton67750fb2008-05-09 22:28:02 +00001232 if (create_options & CREATE_OPTION_READONLY)
1233 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001234
1235 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001236/* pSMB->CreateOptions = cpu_to_le32(create_options &
1237 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001238 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001239
1240 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001241 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001242 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001243 inc_rfc1001_len(pSMB, count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001244
1245 pSMB->ByteCount = cpu_to_le16(count);
1246 /* long_op set to 1 to allow for oplock break timeouts */
1247 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001248 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001249 cifs_stats_inc(&tcon->num_opens);
1250 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001251 cFYI(1, "Error in Open = %d", rc);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001252 } else {
1253 /* BB verify if wct == 15 */
1254
Steve French582d21e2008-05-13 04:54:12 +00001255/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001256
1257 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1258 /* Let caller know file was created so we can set the mode. */
1259 /* Do we care about the CreateAction in any other cases? */
1260 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001261/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001262 *pOplock |= CIFS_CREATE_ACTION; */
1263 /* BB FIXME END */
1264
Steve French790fe572007-07-07 19:25:05 +00001265 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001266 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1267 pfile_info->LastAccessTime = 0; /* BB fixme */
1268 pfile_info->LastWriteTime = 0; /* BB fixme */
1269 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001270 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001271 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001272 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001273 pfile_info->AllocationSize =
1274 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1275 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001276 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001277 pfile_info->DeletePending = 0;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001278 }
1279 }
1280
1281 cifs_buf_release(pSMB);
1282 if (rc == -EAGAIN)
1283 goto OldOpenRetry;
1284 return rc;
1285}
1286
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287int
Steve French96daf2b2011-05-27 04:34:02 +00001288CIFSSMBOpen(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001290 const int access_flags, const int create_options, __u16 *netfid,
1291 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001292 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293{
1294 int rc = -EACCES;
1295 OPEN_REQ *pSMB = NULL;
1296 OPEN_RSP *pSMBr = NULL;
1297 int bytes_returned;
1298 int name_len;
1299 __u16 count;
1300
1301openRetry:
1302 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1303 (void **) &pSMBr);
1304 if (rc)
1305 return rc;
1306
1307 pSMB->AndXCommand = 0xFF; /* none */
1308
1309 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1310 count = 1; /* account for one byte pad to word boundary */
1311 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001312 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1313 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314 name_len++; /* trailing null */
1315 name_len *= 2;
1316 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001317 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318 count = 0; /* no pad */
1319 name_len = strnlen(fileName, PATH_MAX);
1320 name_len++; /* trailing null */
1321 pSMB->NameLength = cpu_to_le16(name_len);
1322 strncpy(pSMB->fileName, fileName, name_len);
1323 }
1324 if (*pOplock & REQ_OPLOCK)
1325 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001326 else if (*pOplock & REQ_BATCHOPLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1329 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -07001330 /* set file as system file if special file such
1331 as fifo and server expecting SFU style and
1332 no Unix extensions */
Steve French790fe572007-07-07 19:25:05 +00001333 if (create_options & CREATE_OPTION_SPECIAL)
Steve Frencheda3c0292005-07-21 15:20:28 -07001334 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1335 else
1336 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Jeff Layton67750fb2008-05-09 22:28:02 +00001337
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338 /* XP does not handle ATTR_POSIX_SEMANTICS */
1339 /* but it helps speed up case sensitive checks for other
1340 servers such as Samba */
1341 if (tcon->ses->capabilities & CAP_UNIX)
1342 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1343
Jeff Layton67750fb2008-05-09 22:28:02 +00001344 if (create_options & CREATE_OPTION_READONLY)
1345 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1346
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1348 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -07001349 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001350 /* BB Expirement with various impersonation levels and verify */
1351 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352 pSMB->SecurityFlags =
1353 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1354
1355 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001356 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357
1358 pSMB->ByteCount = cpu_to_le16(count);
1359 /* long_op set to 1 to allow for oplock break timeouts */
1360 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001361 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001362 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001364 cFYI(1, "Error in Open = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365 } else {
Steve French09d1db52005-04-28 22:41:08 -07001366 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1368 /* Let caller know file was created so we can set the mode. */
1369 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001370 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve French50c2f752007-07-13 00:33:32 +00001371 *pOplock |= CIFS_CREATE_ACTION;
Steve French790fe572007-07-07 19:25:05 +00001372 if (pfile_info) {
Steve French61e74802008-12-03 00:57:54 +00001373 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1374 36 /* CreationTime to Attributes */);
1375 /* the file_info buf is endian converted by caller */
1376 pfile_info->AllocationSize = pSMBr->AllocationSize;
1377 pfile_info->EndOfFile = pSMBr->EndOfFile;
1378 pfile_info->NumberOfLinks = cpu_to_le32(1);
1379 pfile_info->DeletePending = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001382
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383 cifs_buf_release(pSMB);
1384 if (rc == -EAGAIN)
1385 goto openRetry;
1386 return rc;
1387}
1388
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001389struct cifs_readdata *
1390cifs_readdata_alloc(unsigned int nr_pages)
1391{
1392 struct cifs_readdata *rdata;
1393
1394 /* readdata + 1 kvec for each page */
1395 rdata = kzalloc(sizeof(*rdata) +
1396 sizeof(struct kvec) * nr_pages, GFP_KERNEL);
1397 if (rdata != NULL) {
1398 INIT_WORK(&rdata->work, cifs_readv_complete);
1399 INIT_LIST_HEAD(&rdata->pages);
1400 }
1401 return rdata;
1402}
1403
1404void
1405cifs_readdata_free(struct cifs_readdata *rdata)
1406{
1407 cifsFileInfo_put(rdata->cfile);
1408 kfree(rdata);
1409}
1410
1411/*
1412 * Discard any remaining data in the current SMB. To do this, we borrow the
1413 * current bigbuf.
1414 */
1415static int
1416cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1417{
1418 READ_RSP *rsp = (READ_RSP *)server->smallbuf;
1419 unsigned int rfclen = be32_to_cpu(rsp->hdr.smb_buf_length);
1420 int remaining = rfclen + 4 - server->total_read;
1421 struct cifs_readdata *rdata = mid->callback_data;
1422
1423 while (remaining > 0) {
1424 int length;
1425
1426 length = cifs_read_from_socket(server, server->bigbuf,
1427 min_t(unsigned int, remaining,
1428 CIFSMaxBufSize + MAX_CIFS_HDR_SIZE));
1429 if (length < 0)
1430 return length;
1431 server->total_read += length;
1432 remaining -= length;
1433 }
1434
1435 dequeue_mid(mid, rdata->result);
1436 return 0;
1437}
1438
1439static int
1440cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1441{
1442 int length, len;
1443 unsigned int data_offset, remaining, data_len;
1444 struct cifs_readdata *rdata = mid->callback_data;
1445 READ_RSP *rsp = (READ_RSP *)server->smallbuf;
1446 unsigned int rfclen = be32_to_cpu(rsp->hdr.smb_buf_length) + 4;
1447 u64 eof;
1448 pgoff_t eof_index;
1449 struct page *page, *tpage;
1450
1451 cFYI(1, "%s: mid=%u offset=%llu bytes=%u", __func__,
1452 mid->mid, rdata->offset, rdata->bytes);
1453
1454 /*
1455 * read the rest of READ_RSP header (sans Data array), or whatever we
1456 * can if there's not enough data. At this point, we've read down to
1457 * the Mid.
1458 */
1459 len = min_t(unsigned int, rfclen, sizeof(*rsp)) -
1460 sizeof(struct smb_hdr) + 1;
1461
1462 rdata->iov[0].iov_base = server->smallbuf + sizeof(struct smb_hdr) - 1;
1463 rdata->iov[0].iov_len = len;
1464
1465 length = cifs_readv_from_socket(server, rdata->iov, 1, len);
1466 if (length < 0)
1467 return length;
1468 server->total_read += length;
1469
1470 /* Was the SMB read successful? */
1471 rdata->result = map_smb_to_linux_error(&rsp->hdr, false);
1472 if (rdata->result != 0) {
1473 cFYI(1, "%s: server returned error %d", __func__,
1474 rdata->result);
1475 return cifs_readv_discard(server, mid);
1476 }
1477
1478 /* Is there enough to get to the rest of the READ_RSP header? */
1479 if (server->total_read < sizeof(READ_RSP)) {
1480 cFYI(1, "%s: server returned short header. got=%u expected=%zu",
1481 __func__, server->total_read, sizeof(READ_RSP));
1482 rdata->result = -EIO;
1483 return cifs_readv_discard(server, mid);
1484 }
1485
1486 data_offset = le16_to_cpu(rsp->DataOffset) + 4;
1487 if (data_offset < server->total_read) {
1488 /*
1489 * win2k8 sometimes sends an offset of 0 when the read
1490 * is beyond the EOF. Treat it as if the data starts just after
1491 * the header.
1492 */
1493 cFYI(1, "%s: data offset (%u) inside read response header",
1494 __func__, data_offset);
1495 data_offset = server->total_read;
1496 } else if (data_offset > MAX_CIFS_SMALL_BUFFER_SIZE) {
1497 /* data_offset is beyond the end of smallbuf */
1498 cFYI(1, "%s: data offset (%u) beyond end of smallbuf",
1499 __func__, data_offset);
1500 rdata->result = -EIO;
1501 return cifs_readv_discard(server, mid);
1502 }
1503
1504 cFYI(1, "%s: total_read=%u data_offset=%u", __func__,
1505 server->total_read, data_offset);
1506
1507 len = data_offset - server->total_read;
1508 if (len > 0) {
1509 /* read any junk before data into the rest of smallbuf */
1510 rdata->iov[0].iov_base = server->smallbuf + server->total_read;
1511 rdata->iov[0].iov_len = len;
1512 length = cifs_readv_from_socket(server, rdata->iov, 1, len);
1513 if (length < 0)
1514 return length;
1515 server->total_read += length;
1516 }
1517
1518 /* set up first iov for signature check */
1519 rdata->iov[0].iov_base = server->smallbuf;
1520 rdata->iov[0].iov_len = server->total_read;
1521 cFYI(1, "0: iov_base=%p iov_len=%zu",
1522 rdata->iov[0].iov_base, rdata->iov[0].iov_len);
1523
1524 /* how much data is in the response? */
1525 data_len = le16_to_cpu(rsp->DataLengthHigh) << 16;
1526 data_len += le16_to_cpu(rsp->DataLength);
1527 if (data_offset + data_len > rfclen) {
1528 /* data_len is corrupt -- discard frame */
1529 rdata->result = -EIO;
1530 return cifs_readv_discard(server, mid);
1531 }
1532
1533 /* marshal up the page array */
1534 len = 0;
1535 remaining = data_len;
1536 rdata->nr_iov = 1;
1537
1538 /* determine the eof that the server (probably) has */
1539 eof = CIFS_I(rdata->mapping->host)->server_eof;
1540 eof_index = eof ? (eof - 1) >> PAGE_CACHE_SHIFT : 0;
1541 cFYI(1, "eof=%llu eof_index=%lu", eof, eof_index);
1542
1543 list_for_each_entry_safe(page, tpage, &rdata->pages, lru) {
1544 if (remaining >= PAGE_CACHE_SIZE) {
1545 /* enough data to fill the page */
1546 rdata->iov[rdata->nr_iov].iov_base = kmap(page);
1547 rdata->iov[rdata->nr_iov].iov_len = PAGE_CACHE_SIZE;
1548 cFYI(1, "%u: idx=%lu iov_base=%p iov_len=%zu",
1549 rdata->nr_iov, page->index,
1550 rdata->iov[rdata->nr_iov].iov_base,
1551 rdata->iov[rdata->nr_iov].iov_len);
1552 ++rdata->nr_iov;
1553 len += PAGE_CACHE_SIZE;
1554 remaining -= PAGE_CACHE_SIZE;
1555 } else if (remaining > 0) {
1556 /* enough for partial page, fill and zero the rest */
1557 rdata->iov[rdata->nr_iov].iov_base = kmap(page);
1558 rdata->iov[rdata->nr_iov].iov_len = remaining;
1559 cFYI(1, "%u: idx=%lu iov_base=%p iov_len=%zu",
1560 rdata->nr_iov, page->index,
1561 rdata->iov[rdata->nr_iov].iov_base,
1562 rdata->iov[rdata->nr_iov].iov_len);
1563 memset(rdata->iov[rdata->nr_iov].iov_base + remaining,
1564 '\0', PAGE_CACHE_SIZE - remaining);
1565 ++rdata->nr_iov;
1566 len += remaining;
1567 remaining = 0;
1568 } else if (page->index > eof_index) {
1569 /*
1570 * The VFS will not try to do readahead past the
1571 * i_size, but it's possible that we have outstanding
1572 * writes with gaps in the middle and the i_size hasn't
1573 * caught up yet. Populate those with zeroed out pages
1574 * to prevent the VFS from repeatedly attempting to
1575 * fill them until the writes are flushed.
1576 */
1577 zero_user(page, 0, PAGE_CACHE_SIZE);
1578 list_del(&page->lru);
1579 lru_cache_add_file(page);
1580 flush_dcache_page(page);
1581 SetPageUptodate(page);
1582 unlock_page(page);
1583 page_cache_release(page);
1584 } else {
1585 /* no need to hold page hostage */
1586 list_del(&page->lru);
1587 lru_cache_add_file(page);
1588 unlock_page(page);
1589 page_cache_release(page);
1590 }
1591 }
1592
1593 /* issue the read if we have any iovecs left to fill */
1594 if (rdata->nr_iov > 1) {
1595 length = cifs_readv_from_socket(server, &rdata->iov[1],
1596 rdata->nr_iov - 1, len);
1597 if (length < 0)
1598 return length;
1599 server->total_read += length;
1600 } else {
1601 length = 0;
1602 }
1603
1604 rdata->bytes = length;
1605
1606 cFYI(1, "total_read=%u rfclen=%u remaining=%u", server->total_read,
1607 rfclen, remaining);
1608
1609 /* discard anything left over */
1610 if (server->total_read < rfclen)
1611 return cifs_readv_discard(server, mid);
1612
1613 dequeue_mid(mid, false);
1614 return length;
1615}
1616
1617static void
1618cifs_readv_complete(struct work_struct *work)
1619{
1620 struct cifs_readdata *rdata = container_of(work,
1621 struct cifs_readdata, work);
1622 struct page *page, *tpage;
1623
1624 list_for_each_entry_safe(page, tpage, &rdata->pages, lru) {
1625 list_del(&page->lru);
1626 lru_cache_add_file(page);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001627
1628 if (rdata->result == 0) {
Pavel Shilovskya2d6b6c2011-10-21 10:14:04 +04001629 kunmap(page);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001630 flush_dcache_page(page);
1631 SetPageUptodate(page);
1632 }
1633
1634 unlock_page(page);
1635
1636 if (rdata->result == 0)
1637 cifs_readpage_to_fscache(rdata->mapping->host, page);
1638
1639 page_cache_release(page);
1640 }
1641 cifs_readdata_free(rdata);
1642}
1643
1644static void
1645cifs_readv_callback(struct mid_q_entry *mid)
1646{
1647 struct cifs_readdata *rdata = mid->callback_data;
1648 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1649 struct TCP_Server_Info *server = tcon->ses->server;
1650
1651 cFYI(1, "%s: mid=%u state=%d result=%d bytes=%u", __func__,
1652 mid->mid, mid->midState, rdata->result, rdata->bytes);
1653
1654 switch (mid->midState) {
1655 case MID_RESPONSE_RECEIVED:
1656 /* result already set, check signature */
1657 if (server->sec_mode &
1658 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
1659 if (cifs_verify_signature(rdata->iov, rdata->nr_iov,
1660 server, mid->sequence_number + 1))
1661 cERROR(1, "Unexpected SMB signature");
1662 }
1663 /* FIXME: should this be counted toward the initiating task? */
1664 task_io_account_read(rdata->bytes);
1665 cifs_stats_bytes_read(tcon, rdata->bytes);
1666 break;
1667 case MID_REQUEST_SUBMITTED:
1668 case MID_RETRY_NEEDED:
1669 rdata->result = -EAGAIN;
1670 break;
1671 default:
1672 rdata->result = -EIO;
1673 }
1674
1675 queue_work(system_nrt_wq, &rdata->work);
1676 DeleteMidQEntry(mid);
1677 atomic_dec(&server->inFlight);
1678 wake_up(&server->request_q);
1679}
1680
1681/* cifs_async_readv - send an async write, and set up mid to handle result */
1682int
1683cifs_async_readv(struct cifs_readdata *rdata)
1684{
1685 int rc;
1686 READ_REQ *smb = NULL;
1687 int wct;
1688 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1689
1690 cFYI(1, "%s: offset=%llu bytes=%u", __func__,
1691 rdata->offset, rdata->bytes);
1692
1693 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1694 wct = 12;
1695 else {
1696 wct = 10; /* old style read */
1697 if ((rdata->offset >> 32) > 0) {
1698 /* can not handle this big offset for old */
1699 return -EIO;
1700 }
1701 }
1702
1703 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **)&smb);
1704 if (rc)
1705 return rc;
1706
1707 smb->hdr.Pid = cpu_to_le16((__u16)rdata->pid);
1708 smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16));
1709
1710 smb->AndXCommand = 0xFF; /* none */
1711 smb->Fid = rdata->cfile->netfid;
1712 smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF);
1713 if (wct == 12)
1714 smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32);
1715 smb->Remaining = 0;
1716 smb->MaxCount = cpu_to_le16(rdata->bytes & 0xFFFF);
1717 smb->MaxCountHigh = cpu_to_le32(rdata->bytes >> 16);
1718 if (wct == 12)
1719 smb->ByteCount = 0;
1720 else {
1721 /* old style read */
1722 struct smb_com_readx_req *smbr =
1723 (struct smb_com_readx_req *)smb;
1724 smbr->ByteCount = 0;
1725 }
1726
1727 /* 4 for RFC1001 length + 1 for BCC */
1728 rdata->iov[0].iov_base = smb;
1729 rdata->iov[0].iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
1730
1731 rc = cifs_call_async(tcon->ses->server, rdata->iov, 1,
1732 cifs_readv_receive, cifs_readv_callback,
1733 rdata, false);
1734
1735 if (rc == 0)
1736 cifs_stats_inc(&tcon->num_reads);
1737
1738 cifs_small_buf_release(smb);
1739 return rc;
1740}
1741
Linus Torvalds1da177e2005-04-16 15:20:36 -07001742int
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001743CIFSSMBRead(const int xid, struct cifs_io_parms *io_parms, unsigned int *nbytes,
Steve French50c2f752007-07-13 00:33:32 +00001744 char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745{
1746 int rc = -EACCES;
1747 READ_REQ *pSMB = NULL;
1748 READ_RSP *pSMBr = NULL;
1749 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001750 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001751 int resp_buf_type = 0;
1752 struct kvec iov[1];
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001753 __u32 pid = io_parms->pid;
1754 __u16 netfid = io_parms->netfid;
1755 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001756 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001757 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758
Joe Perchesb6b38f72010-04-21 03:50:45 +00001759 cFYI(1, "Reading %d bytes on fid %d", count, netfid);
Steve French790fe572007-07-07 19:25:05 +00001760 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001761 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001762 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001763 wct = 10; /* old style read */
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001764 if ((offset >> 32) > 0) {
Steve French4c3130e2008-12-09 00:28:16 +00001765 /* can not handle this big offset for old */
1766 return -EIO;
1767 }
1768 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769
1770 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001771 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772 if (rc)
1773 return rc;
1774
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001775 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1776 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1777
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778 /* tcon and ses pointer are checked in smb_init */
1779 if (tcon->ses->server == NULL)
1780 return -ECONNABORTED;
1781
Steve Frenchec637e32005-12-12 20:53:18 -08001782 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783 pSMB->Fid = netfid;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001784 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001785 if (wct == 12)
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001786 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001787
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788 pSMB->Remaining = 0;
1789 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1790 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001791 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001792 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1793 else {
1794 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001795 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001796 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001797 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001798 }
Steve Frenchec637e32005-12-12 20:53:18 -08001799
1800 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001801 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve Frencha761ac52007-10-18 21:45:27 +00001802 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Jeff Layton77499812011-01-11 07:24:23 -05001803 &resp_buf_type, CIFS_LOG_ERROR);
Steve Frencha4544342005-08-24 13:59:35 -07001804 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001805 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001806 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001807 cERROR(1, "Send error in read = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808 } else {
1809 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1810 data_length = data_length << 16;
1811 data_length += le16_to_cpu(pSMBr->DataLength);
1812 *nbytes = data_length;
1813
1814 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001815 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001816 || (data_length > count)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001817 cFYI(1, "bad length %d for count %d",
1818 data_length, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819 rc = -EIO;
1820 *nbytes = 0;
1821 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001822 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001823 le16_to_cpu(pSMBr->DataOffset);
1824/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001825 cERROR(1, "Faulting on read rc = %d",rc);
Steve French50c2f752007-07-13 00:33:32 +00001826 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001827 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001828 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001829 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830 }
1831 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832
Steve French4b8f9302006-02-26 16:41:18 +00001833/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001834 if (*buf) {
1835 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001836 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001837 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001838 cifs_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001839 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001840 /* return buffer to caller to free */
1841 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001842 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001843 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001844 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001845 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001846 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001847
1848 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849 since file handle passed in no longer valid */
1850 return rc;
1851}
1852
Steve Frenchec637e32005-12-12 20:53:18 -08001853
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854int
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001855CIFSSMBWrite(const int xid, struct cifs_io_parms *io_parms,
1856 unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001857 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858{
1859 int rc = -EACCES;
1860 WRITE_REQ *pSMB = NULL;
1861 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001862 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863 __u32 bytes_sent;
1864 __u16 byte_count;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001865 __u32 pid = io_parms->pid;
1866 __u16 netfid = io_parms->netfid;
1867 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001868 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001869 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870
Steve Frencha24e2d72010-04-03 17:20:21 +00001871 *nbytes = 0;
1872
Joe Perchesb6b38f72010-04-21 03:50:45 +00001873 /* cFYI(1, "write at %lld %d bytes", offset, count);*/
Steve French790fe572007-07-07 19:25:05 +00001874 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001875 return -ECONNABORTED;
1876
Steve French790fe572007-07-07 19:25:05 +00001877 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001878 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001879 else {
Steve French1c955182005-08-30 20:58:07 -07001880 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001881 if ((offset >> 32) > 0) {
1882 /* can not handle big offset for old srv */
1883 return -EIO;
1884 }
1885 }
Steve French1c955182005-08-30 20:58:07 -07001886
1887 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888 (void **) &pSMBr);
1889 if (rc)
1890 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001891
1892 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1893 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1894
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895 /* tcon and ses pointer are checked in smb_init */
1896 if (tcon->ses->server == NULL)
1897 return -ECONNABORTED;
1898
1899 pSMB->AndXCommand = 0xFF; /* none */
1900 pSMB->Fid = netfid;
1901 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001902 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001903 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001904
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905 pSMB->Reserved = 0xFFFFFFFF;
1906 pSMB->WriteMode = 0;
1907 pSMB->Remaining = 0;
1908
Steve French50c2f752007-07-13 00:33:32 +00001909 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910 can send more if LARGE_WRITE_X capability returned by the server and if
1911 our buffer is big enough or if we convert to iovecs on socket writes
1912 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001913 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001914 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1915 } else {
1916 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1917 & ~0xFF;
1918 }
1919
1920 if (bytes_sent > count)
1921 bytes_sent = count;
1922 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001923 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001924 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001925 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001926 else if (ubuf) {
1927 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928 cifs_buf_release(pSMB);
1929 return -EFAULT;
1930 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001931 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932 /* No buffer */
1933 cifs_buf_release(pSMB);
1934 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001935 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001936 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001937 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001938 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001939 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001940
Linus Torvalds1da177e2005-04-16 15:20:36 -07001941 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1942 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001943 inc_rfc1001_len(pSMB, byte_count);
Steve French1c955182005-08-30 20:58:07 -07001944
Steve French790fe572007-07-07 19:25:05 +00001945 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001946 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001947 else { /* old style write has byte count 4 bytes earlier
1948 so 4 bytes pad */
1949 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001950 (struct smb_com_writex_req *)pSMB;
1951 pSMBW->ByteCount = cpu_to_le16(byte_count);
1952 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953
1954 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1955 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001956 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001957 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00001958 cFYI(1, "Send error in write = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959 } else {
1960 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1961 *nbytes = (*nbytes) << 16;
1962 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301963
1964 /*
1965 * Mask off high 16 bits when bytes written as returned by the
1966 * server is greater than bytes requested by the client. Some
1967 * OS/2 servers are known to set incorrect CountHigh values.
1968 */
1969 if (*nbytes > count)
1970 *nbytes &= 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001971 }
1972
1973 cifs_buf_release(pSMB);
1974
Steve French50c2f752007-07-13 00:33:32 +00001975 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976 since file handle passed in no longer valid */
1977
1978 return rc;
1979}
1980
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001981void
1982cifs_writedata_release(struct kref *refcount)
1983{
1984 struct cifs_writedata *wdata = container_of(refcount,
1985 struct cifs_writedata, refcount);
1986
1987 if (wdata->cfile)
1988 cifsFileInfo_put(wdata->cfile);
1989
1990 kfree(wdata);
1991}
1992
1993/*
1994 * Write failed with a retryable error. Resend the write request. It's also
1995 * possible that the page was redirtied so re-clean the page.
1996 */
1997static void
1998cifs_writev_requeue(struct cifs_writedata *wdata)
1999{
2000 int i, rc;
2001 struct inode *inode = wdata->cfile->dentry->d_inode;
2002
2003 for (i = 0; i < wdata->nr_pages; i++) {
2004 lock_page(wdata->pages[i]);
2005 clear_page_dirty_for_io(wdata->pages[i]);
2006 }
2007
2008 do {
2009 rc = cifs_async_writev(wdata);
2010 } while (rc == -EAGAIN);
2011
2012 for (i = 0; i < wdata->nr_pages; i++) {
2013 if (rc != 0)
2014 SetPageError(wdata->pages[i]);
2015 unlock_page(wdata->pages[i]);
2016 }
2017
2018 mapping_set_error(inode->i_mapping, rc);
2019 kref_put(&wdata->refcount, cifs_writedata_release);
2020}
2021
2022static void
2023cifs_writev_complete(struct work_struct *work)
2024{
2025 struct cifs_writedata *wdata = container_of(work,
2026 struct cifs_writedata, work);
2027 struct inode *inode = wdata->cfile->dentry->d_inode;
2028 int i = 0;
2029
2030 if (wdata->result == 0) {
2031 cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
2032 cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
2033 wdata->bytes);
2034 } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
2035 return cifs_writev_requeue(wdata);
2036
2037 for (i = 0; i < wdata->nr_pages; i++) {
2038 struct page *page = wdata->pages[i];
2039 if (wdata->result == -EAGAIN)
2040 __set_page_dirty_nobuffers(page);
2041 else if (wdata->result < 0)
2042 SetPageError(page);
2043 end_page_writeback(page);
2044 page_cache_release(page);
2045 }
2046 if (wdata->result != -EAGAIN)
2047 mapping_set_error(inode->i_mapping, wdata->result);
2048 kref_put(&wdata->refcount, cifs_writedata_release);
2049}
2050
2051struct cifs_writedata *
2052cifs_writedata_alloc(unsigned int nr_pages)
2053{
2054 struct cifs_writedata *wdata;
2055
2056 /* this would overflow */
2057 if (nr_pages == 0) {
2058 cERROR(1, "%s: called with nr_pages == 0!", __func__);
2059 return NULL;
2060 }
2061
2062 /* writedata + number of page pointers */
2063 wdata = kzalloc(sizeof(*wdata) +
2064 sizeof(struct page *) * (nr_pages - 1), GFP_NOFS);
2065 if (wdata != NULL) {
2066 INIT_WORK(&wdata->work, cifs_writev_complete);
2067 kref_init(&wdata->refcount);
2068 }
2069 return wdata;
2070}
2071
2072/*
2073 * Check the midState and signature on received buffer (if any), and queue the
2074 * workqueue completion task.
2075 */
2076static void
2077cifs_writev_callback(struct mid_q_entry *mid)
2078{
2079 struct cifs_writedata *wdata = mid->callback_data;
Steve French96daf2b2011-05-27 04:34:02 +00002080 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002081 unsigned int written;
2082 WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
2083
2084 switch (mid->midState) {
2085 case MID_RESPONSE_RECEIVED:
2086 wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
2087 if (wdata->result != 0)
2088 break;
2089
2090 written = le16_to_cpu(smb->CountHigh);
2091 written <<= 16;
2092 written += le16_to_cpu(smb->Count);
2093 /*
2094 * Mask off high 16 bits when bytes written as returned
2095 * by the server is greater than bytes requested by the
2096 * client. OS/2 servers are known to set incorrect
2097 * CountHigh values.
2098 */
2099 if (written > wdata->bytes)
2100 written &= 0xFFFF;
2101
2102 if (written < wdata->bytes)
2103 wdata->result = -ENOSPC;
2104 else
2105 wdata->bytes = written;
2106 break;
2107 case MID_REQUEST_SUBMITTED:
2108 case MID_RETRY_NEEDED:
2109 wdata->result = -EAGAIN;
2110 break;
2111 default:
2112 wdata->result = -EIO;
2113 break;
2114 }
2115
2116 queue_work(system_nrt_wq, &wdata->work);
2117 DeleteMidQEntry(mid);
2118 atomic_dec(&tcon->ses->server->inFlight);
2119 wake_up(&tcon->ses->server->request_q);
2120}
2121
2122/* cifs_async_writev - send an async write, and set up mid to handle result */
2123int
2124cifs_async_writev(struct cifs_writedata *wdata)
2125{
2126 int i, rc = -EACCES;
2127 WRITE_REQ *smb = NULL;
2128 int wct;
Steve French96daf2b2011-05-27 04:34:02 +00002129 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002130 struct inode *inode = wdata->cfile->dentry->d_inode;
2131 struct kvec *iov = NULL;
2132
2133 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
2134 wct = 14;
2135 } else {
2136 wct = 12;
2137 if (wdata->offset >> 32 > 0) {
2138 /* can not handle big offset for old srv */
2139 return -EIO;
2140 }
2141 }
2142
2143 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
2144 if (rc)
2145 goto async_writev_out;
2146
2147 /* 1 iov per page + 1 for header */
2148 iov = kzalloc((wdata->nr_pages + 1) * sizeof(*iov), GFP_NOFS);
2149 if (iov == NULL) {
2150 rc = -ENOMEM;
2151 goto async_writev_out;
2152 }
2153
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002154 smb->hdr.Pid = cpu_to_le16((__u16)wdata->cfile->pid);
2155 smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->cfile->pid >> 16));
2156
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002157 smb->AndXCommand = 0xFF; /* none */
2158 smb->Fid = wdata->cfile->netfid;
2159 smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
2160 if (wct == 14)
2161 smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
2162 smb->Reserved = 0xFFFFFFFF;
2163 smb->WriteMode = 0;
2164 smb->Remaining = 0;
2165
2166 smb->DataOffset =
2167 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
2168
2169 /* 4 for RFC1001 length + 1 for BCC */
2170 iov[0].iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4 + 1;
2171 iov[0].iov_base = smb;
2172
2173 /* marshal up the pages into iov array */
2174 wdata->bytes = 0;
2175 for (i = 0; i < wdata->nr_pages; i++) {
2176 iov[i + 1].iov_len = min(inode->i_size -
2177 page_offset(wdata->pages[i]),
2178 (loff_t)PAGE_CACHE_SIZE);
2179 iov[i + 1].iov_base = kmap(wdata->pages[i]);
2180 wdata->bytes += iov[i + 1].iov_len;
2181 }
2182
2183 cFYI(1, "async write at %llu %u bytes", wdata->offset, wdata->bytes);
2184
2185 smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
2186 smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16);
2187
2188 if (wct == 14) {
2189 inc_rfc1001_len(&smb->hdr, wdata->bytes + 1);
2190 put_bcc(wdata->bytes + 1, &smb->hdr);
2191 } else {
2192 /* wct == 12 */
2193 struct smb_com_writex_req *smbw =
2194 (struct smb_com_writex_req *)smb;
2195 inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
2196 put_bcc(wdata->bytes + 5, &smbw->hdr);
2197 iov[0].iov_len += 4; /* pad bigger by four bytes */
2198 }
2199
2200 kref_get(&wdata->refcount);
2201 rc = cifs_call_async(tcon->ses->server, iov, wdata->nr_pages + 1,
Jeff Layton44d22d82011-10-19 15:29:49 -04002202 NULL, cifs_writev_callback, wdata, false);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002203
2204 if (rc == 0)
2205 cifs_stats_inc(&tcon->num_writes);
2206 else
2207 kref_put(&wdata->refcount, cifs_writedata_release);
2208
2209 /* send is done, unmap pages */
2210 for (i = 0; i < wdata->nr_pages; i++)
2211 kunmap(wdata->pages[i]);
2212
2213async_writev_out:
2214 cifs_small_buf_release(smb);
2215 kfree(iov);
2216 return rc;
2217}
2218
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002219int
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002220CIFSSMBWrite2(const int xid, struct cifs_io_parms *io_parms,
2221 unsigned int *nbytes, struct kvec *iov, int n_vec,
2222 const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002223{
2224 int rc = -EACCES;
2225 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08002226 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002227 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08002228 int resp_buf_type = 0;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002229 __u32 pid = io_parms->pid;
2230 __u16 netfid = io_parms->netfid;
2231 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00002232 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002233 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002234
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04002235 *nbytes = 0;
2236
Joe Perchesb6b38f72010-04-21 03:50:45 +00002237 cFYI(1, "write2 at %lld %d bytes", (long long)offset, count);
Steve Frenchff7feac2005-11-15 16:45:16 -08002238
Steve French4c3130e2008-12-09 00:28:16 +00002239 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07002240 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00002241 } else {
Steve French8cc64c62005-10-03 13:49:43 -07002242 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00002243 if ((offset >> 32) > 0) {
2244 /* can not handle big offset for old srv */
2245 return -EIO;
2246 }
2247 }
Steve French8cc64c62005-10-03 13:49:43 -07002248 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002249 if (rc)
2250 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002251
2252 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
2253 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
2254
Linus Torvalds1da177e2005-04-16 15:20:36 -07002255 /* tcon and ses pointer are checked in smb_init */
2256 if (tcon->ses->server == NULL)
2257 return -ECONNABORTED;
2258
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002259 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002260 pSMB->Fid = netfid;
2261 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00002262 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002263 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002264 pSMB->Reserved = 0xFFFFFFFF;
2265 pSMB->WriteMode = 0;
2266 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002267
Linus Torvalds1da177e2005-04-16 15:20:36 -07002268 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00002269 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002270
Steve French3e844692005-10-03 13:37:24 -07002271 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
2272 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002273 /* header + 1 byte pad */
2274 smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
Steve French790fe572007-07-07 19:25:05 +00002275 if (wct == 14)
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002276 inc_rfc1001_len(pSMB, count + 1);
Steve French8cc64c62005-10-03 13:49:43 -07002277 else /* wct == 12 */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002278 inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
Steve French790fe572007-07-07 19:25:05 +00002279 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002280 pSMB->ByteCount = cpu_to_le16(count + 1);
2281 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00002282 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07002283 (struct smb_com_writex_req *)pSMB;
2284 pSMBW->ByteCount = cpu_to_le16(count + 5);
2285 }
Steve French3e844692005-10-03 13:37:24 -07002286 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00002287 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08002288 iov[0].iov_len = smb_hdr_len + 4;
2289 else /* wct == 12 pad bigger by four bytes */
2290 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00002291
Steve French3e844692005-10-03 13:37:24 -07002292
Steve Frenchec637e32005-12-12 20:53:18 -08002293 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French133672e2007-11-13 22:41:37 +00002294 long_op);
Steve Frencha4544342005-08-24 13:59:35 -07002295 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002296 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002297 cFYI(1, "Send error Write2 = %d", rc);
Steve French790fe572007-07-07 19:25:05 +00002298 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08002299 /* presumably this can not happen, but best to be safe */
2300 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002301 } else {
Steve Frenchad7a2922008-02-07 23:25:02 +00002302 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002303 *nbytes = le16_to_cpu(pSMBr->CountHigh);
2304 *nbytes = (*nbytes) << 16;
2305 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05302306
2307 /*
2308 * Mask off high 16 bits when bytes written as returned by the
2309 * server is greater than bytes requested by the client. OS/2
2310 * servers are known to set incorrect CountHigh values.
2311 */
2312 if (*nbytes > count)
2313 *nbytes &= 0xFFFF;
Steve French50c2f752007-07-13 00:33:32 +00002314 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002315
Steve French4b8f9302006-02-26 16:41:18 +00002316/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00002317 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002318 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00002319 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002320 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002321
Steve French50c2f752007-07-13 00:33:32 +00002322 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323 since file handle passed in no longer valid */
2324
2325 return rc;
2326}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002327
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002328int cifs_lockv(const int xid, struct cifs_tcon *tcon, const __u16 netfid,
2329 const __u8 lock_type, const __u32 num_unlock,
2330 const __u32 num_lock, LOCKING_ANDX_RANGE *buf)
2331{
2332 int rc = 0;
2333 LOCK_REQ *pSMB = NULL;
2334 struct kvec iov[2];
2335 int resp_buf_type;
2336 __u16 count;
2337
2338 cFYI(1, "cifs_lockv num lock %d num unlock %d", num_lock, num_unlock);
2339
2340 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2341 if (rc)
2342 return rc;
2343
2344 pSMB->Timeout = 0;
2345 pSMB->NumberOfLocks = cpu_to_le16(num_lock);
2346 pSMB->NumberOfUnlocks = cpu_to_le16(num_unlock);
2347 pSMB->LockType = lock_type;
2348 pSMB->AndXCommand = 0xFF; /* none */
2349 pSMB->Fid = netfid; /* netfid stays le */
2350
2351 count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2352 inc_rfc1001_len(pSMB, count);
2353 pSMB->ByteCount = cpu_to_le16(count);
2354
2355 iov[0].iov_base = (char *)pSMB;
2356 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 -
2357 (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2358 iov[1].iov_base = (char *)buf;
2359 iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2360
2361 cifs_stats_inc(&tcon->num_locks);
2362 rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP);
2363 if (rc)
2364 cFYI(1, "Send error in cifs_lockv = %d", rc);
2365
2366 return rc;
2367}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002368
Linus Torvalds1da177e2005-04-16 15:20:36 -07002369int
Steve French96daf2b2011-05-27 04:34:02 +00002370CIFSSMBLock(const int xid, struct cifs_tcon *tcon,
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002371 const __u16 smb_file_id, const __u32 netpid, const __u64 len,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002372 const __u64 offset, const __u32 numUnlock,
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002373 const __u32 numLock, const __u8 lockType,
2374 const bool waitFlag, const __u8 oplock_level)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002375{
2376 int rc = 0;
2377 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002378/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002379 int bytes_returned;
2380 int timeout = 0;
2381 __u16 count;
2382
Joe Perchesb6b38f72010-04-21 03:50:45 +00002383 cFYI(1, "CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock);
Steve French46810cb2005-04-28 22:41:09 -07002384 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2385
Linus Torvalds1da177e2005-04-16 15:20:36 -07002386 if (rc)
2387 return rc;
2388
Steve French790fe572007-07-07 19:25:05 +00002389 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Steve French133672e2007-11-13 22:41:37 +00002390 timeout = CIFS_ASYNC_OP; /* no response expected */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002391 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00002392 } else if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00002393 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002394 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
2395 } else {
2396 pSMB->Timeout = 0;
2397 }
2398
2399 pSMB->NumberOfLocks = cpu_to_le16(numLock);
2400 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
2401 pSMB->LockType = lockType;
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002402 pSMB->OplockLevel = oplock_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002403 pSMB->AndXCommand = 0xFF; /* none */
2404 pSMB->Fid = smb_file_id; /* netfid stays le */
2405
Steve French790fe572007-07-07 19:25:05 +00002406 if ((numLock != 0) || (numUnlock != 0)) {
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002407 pSMB->Locks[0].Pid = cpu_to_le16(netpid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408 /* BB where to store pid high? */
2409 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
2410 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
2411 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
2412 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
2413 count = sizeof(LOCKING_ANDX_RANGE);
2414 } else {
2415 /* oplock break */
2416 count = 0;
2417 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002418 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002419 pSMB->ByteCount = cpu_to_le16(count);
2420
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002421 if (waitFlag) {
2422 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002423 (struct smb_hdr *) pSMB, &bytes_returned);
Steve French133672e2007-11-13 22:41:37 +00002424 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002425 } else {
Steve French133672e2007-11-13 22:41:37 +00002426 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
2427 timeout);
2428 /* SMB buffer freed by function above */
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002429 }
Steve Frencha4544342005-08-24 13:59:35 -07002430 cifs_stats_inc(&tcon->num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002431 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002432 cFYI(1, "Send error in Lock = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002433
Steve French50c2f752007-07-13 00:33:32 +00002434 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002435 since file handle passed in no longer valid */
2436 return rc;
2437}
2438
2439int
Steve French96daf2b2011-05-27 04:34:02 +00002440CIFSSMBPosixLock(const int xid, struct cifs_tcon *tcon,
Pavel Shilovsky4f6bcec2011-10-22 15:33:30 +04002441 const __u16 smb_file_id, const __u32 netpid, const int get_flag,
2442 const __u64 len, struct file_lock *pLockData,
2443 const __u16 lock_type, const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00002444{
2445 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2446 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00002447 struct cifs_posix_lock *parm_data;
2448 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00002449 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00002450 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00002451 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00002452 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00002453 struct kvec iov[1];
Steve French08547b02006-02-28 22:39:25 +00002454
Joe Perchesb6b38f72010-04-21 03:50:45 +00002455 cFYI(1, "Posix Lock");
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002456
Steve French790fe572007-07-07 19:25:05 +00002457 if (pLockData == NULL)
Marcin Slusarzed5f0372008-05-13 04:01:01 +00002458 return -EINVAL;
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002459
Steve French08547b02006-02-28 22:39:25 +00002460 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
2461
2462 if (rc)
2463 return rc;
2464
2465 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
2466
Steve French50c2f752007-07-13 00:33:32 +00002467 params = 6;
Steve French08547b02006-02-28 22:39:25 +00002468 pSMB->MaxSetupCount = 0;
2469 pSMB->Reserved = 0;
2470 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00002471 pSMB->Reserved2 = 0;
2472 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2473 offset = param_offset + params;
2474
Steve French08547b02006-02-28 22:39:25 +00002475 count = sizeof(struct cifs_posix_lock);
2476 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002477 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00002478 pSMB->SetupCount = 1;
2479 pSMB->Reserved3 = 0;
Steve French790fe572007-07-07 19:25:05 +00002480 if (get_flag)
Steve French08547b02006-02-28 22:39:25 +00002481 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2482 else
2483 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2484 byte_count = 3 /* pad */ + params + count;
2485 pSMB->DataCount = cpu_to_le16(count);
2486 pSMB->ParameterCount = cpu_to_le16(params);
2487 pSMB->TotalDataCount = pSMB->DataCount;
2488 pSMB->TotalParameterCount = pSMB->ParameterCount;
2489 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00002490 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00002491 (((char *) &pSMB->hdr.Protocol) + offset);
2492
2493 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00002494 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00002495 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00002496 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00002497 pSMB->Timeout = cpu_to_le32(-1);
2498 } else
2499 pSMB->Timeout = 0;
2500
Pavel Shilovsky4f6bcec2011-10-22 15:33:30 +04002501 parm_data->pid = cpu_to_le32(netpid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002502 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00002503 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00002504
2505 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00002506 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00002507 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
2508 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002509 inc_rfc1001_len(pSMB, byte_count);
Steve French08547b02006-02-28 22:39:25 +00002510 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002511 if (waitFlag) {
2512 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2513 (struct smb_hdr *) pSMBr, &bytes_returned);
2514 } else {
Steve French133672e2007-11-13 22:41:37 +00002515 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002516 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French133672e2007-11-13 22:41:37 +00002517 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
2518 &resp_buf_type, timeout);
2519 pSMB = NULL; /* request buf already freed by SendReceive2. Do
2520 not try to free it twice below on exit */
2521 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002522 }
2523
Steve French08547b02006-02-28 22:39:25 +00002524 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002525 cFYI(1, "Send error in Posix Lock = %d", rc);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002526 } else if (get_flag) {
2527 /* lock structure can be returned on get */
2528 __u16 data_offset;
2529 __u16 data_count;
2530 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00002531
Jeff Layton820a8032011-05-04 08:05:26 -04002532 if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002533 rc = -EIO; /* bad smb */
2534 goto plk_err_exit;
2535 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002536 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2537 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00002538 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002539 rc = -EIO;
2540 goto plk_err_exit;
2541 }
2542 parm_data = (struct cifs_posix_lock *)
2543 ((char *)&pSMBr->hdr.Protocol + data_offset);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002544 if (parm_data->lock_type == __constant_cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002545 pLockData->fl_type = F_UNLCK;
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002546 else {
2547 if (parm_data->lock_type ==
2548 __constant_cpu_to_le16(CIFS_RDLCK))
2549 pLockData->fl_type = F_RDLCK;
2550 else if (parm_data->lock_type ==
2551 __constant_cpu_to_le16(CIFS_WRLCK))
2552 pLockData->fl_type = F_WRLCK;
2553
Steve French5443d132011-03-13 05:08:25 +00002554 pLockData->fl_start = le64_to_cpu(parm_data->start);
2555 pLockData->fl_end = pLockData->fl_start +
2556 le64_to_cpu(parm_data->length) - 1;
2557 pLockData->fl_pid = le32_to_cpu(parm_data->pid);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002558 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002559 }
Steve French50c2f752007-07-13 00:33:32 +00002560
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002561plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00002562 if (pSMB)
2563 cifs_small_buf_release(pSMB);
2564
Steve French133672e2007-11-13 22:41:37 +00002565 if (resp_buf_type == CIFS_SMALL_BUFFER)
2566 cifs_small_buf_release(iov[0].iov_base);
2567 else if (resp_buf_type == CIFS_LARGE_BUFFER)
2568 cifs_buf_release(iov[0].iov_base);
2569
Steve French08547b02006-02-28 22:39:25 +00002570 /* Note: On -EAGAIN error only caller can retry on handle based calls
2571 since file handle passed in no longer valid */
2572
2573 return rc;
2574}
2575
2576
2577int
Steve French96daf2b2011-05-27 04:34:02 +00002578CIFSSMBClose(const int xid, struct cifs_tcon *tcon, int smb_file_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002579{
2580 int rc = 0;
2581 CLOSE_REQ *pSMB = NULL;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002582 cFYI(1, "In CIFSSMBClose");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002583
2584/* do not retry on dead session on close */
2585 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00002586 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002587 return 0;
2588 if (rc)
2589 return rc;
2590
Linus Torvalds1da177e2005-04-16 15:20:36 -07002591 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00002592 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002593 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00002594 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002595 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002596 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00002597 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002598 /* EINTR is expected when user ctl-c to kill app */
Joe Perchesb6b38f72010-04-21 03:50:45 +00002599 cERROR(1, "Send error in Close = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002600 }
2601 }
2602
Linus Torvalds1da177e2005-04-16 15:20:36 -07002603 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00002604 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002605 rc = 0;
2606
2607 return rc;
2608}
2609
2610int
Steve French96daf2b2011-05-27 04:34:02 +00002611CIFSSMBFlush(const int xid, struct cifs_tcon *tcon, int smb_file_id)
Steve Frenchb298f222009-02-21 21:17:43 +00002612{
2613 int rc = 0;
2614 FLUSH_REQ *pSMB = NULL;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002615 cFYI(1, "In CIFSSMBFlush");
Steve Frenchb298f222009-02-21 21:17:43 +00002616
2617 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
2618 if (rc)
2619 return rc;
2620
2621 pSMB->FileID = (__u16) smb_file_id;
2622 pSMB->ByteCount = 0;
2623 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
2624 cifs_stats_inc(&tcon->num_flushes);
2625 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002626 cERROR(1, "Send error in Flush = %d", rc);
Steve Frenchb298f222009-02-21 21:17:43 +00002627
2628 return rc;
2629}
2630
2631int
Steve French96daf2b2011-05-27 04:34:02 +00002632CIFSSMBRename(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002633 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002634 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635{
2636 int rc = 0;
2637 RENAME_REQ *pSMB = NULL;
2638 RENAME_RSP *pSMBr = NULL;
2639 int bytes_returned;
2640 int name_len, name_len2;
2641 __u16 count;
2642
Joe Perchesb6b38f72010-04-21 03:50:45 +00002643 cFYI(1, "In CIFSSMBRename");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002644renameRetry:
2645 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
2646 (void **) &pSMBr);
2647 if (rc)
2648 return rc;
2649
2650 pSMB->BufferFormat = 0x04;
2651 pSMB->SearchAttributes =
2652 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2653 ATTR_DIRECTORY);
2654
2655 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2656 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06002657 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, fromName,
2658 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002659 name_len++; /* trailing null */
2660 name_len *= 2;
2661 pSMB->OldFileName[name_len] = 0x04; /* pad */
2662 /* protocol requires ASCII signature byte on Unicode string */
2663 pSMB->OldFileName[name_len + 1] = 0x00;
2664 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002665 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2666 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002667 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2668 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002669 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002670 name_len = strnlen(fromName, PATH_MAX);
2671 name_len++; /* trailing null */
2672 strncpy(pSMB->OldFileName, fromName, name_len);
2673 name_len2 = strnlen(toName, PATH_MAX);
2674 name_len2++; /* trailing null */
2675 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2676 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2677 name_len2++; /* trailing null */
2678 name_len2++; /* signature byte */
2679 }
2680
2681 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002682 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002683 pSMB->ByteCount = cpu_to_le16(count);
2684
2685 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2686 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002687 cifs_stats_inc(&tcon->num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002688 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002689 cFYI(1, "Send error in rename = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002690
Linus Torvalds1da177e2005-04-16 15:20:36 -07002691 cifs_buf_release(pSMB);
2692
2693 if (rc == -EAGAIN)
2694 goto renameRetry;
2695
2696 return rc;
2697}
2698
Steve French96daf2b2011-05-27 04:34:02 +00002699int CIFSSMBRenameOpenFile(const int xid, struct cifs_tcon *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002700 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002701 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002702{
2703 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2704 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002705 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002706 char *data_offset;
2707 char dummy_string[30];
2708 int rc = 0;
2709 int bytes_returned = 0;
2710 int len_of_str;
2711 __u16 params, param_offset, offset, count, byte_count;
2712
Joe Perchesb6b38f72010-04-21 03:50:45 +00002713 cFYI(1, "Rename to File by handle");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002714 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2715 (void **) &pSMBr);
2716 if (rc)
2717 return rc;
2718
2719 params = 6;
2720 pSMB->MaxSetupCount = 0;
2721 pSMB->Reserved = 0;
2722 pSMB->Flags = 0;
2723 pSMB->Timeout = 0;
2724 pSMB->Reserved2 = 0;
2725 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2726 offset = param_offset + params;
2727
2728 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2729 rename_info = (struct set_file_rename *) data_offset;
2730 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002731 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002732 pSMB->SetupCount = 1;
2733 pSMB->Reserved3 = 0;
2734 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2735 byte_count = 3 /* pad */ + params;
2736 pSMB->ParameterCount = cpu_to_le16(params);
2737 pSMB->TotalParameterCount = pSMB->ParameterCount;
2738 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2739 pSMB->DataOffset = cpu_to_le16(offset);
2740 /* construct random name ".cifs_tmp<inodenum><mid>" */
2741 rename_info->overwrite = cpu_to_le32(1);
2742 rename_info->root_fid = 0;
2743 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002744 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002745 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
Steve Frenchacbbb762012-01-18 22:32:33 -06002746 len_of_str =
2747 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002748 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002749 } else {
Steve Frenchacbbb762012-01-18 22:32:33 -06002750 len_of_str =
2751 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002752 target_name, PATH_MAX, nls_codepage,
2753 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002754 }
2755 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002756 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002757 byte_count += count;
2758 pSMB->DataCount = cpu_to_le16(count);
2759 pSMB->TotalDataCount = pSMB->DataCount;
2760 pSMB->Fid = netfid;
2761 pSMB->InformationLevel =
2762 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2763 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002764 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002765 pSMB->ByteCount = cpu_to_le16(byte_count);
2766 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002767 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002768 cifs_stats_inc(&pTcon->num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002769 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002770 cFYI(1, "Send error in Rename (by file handle) = %d", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07002771
Linus Torvalds1da177e2005-04-16 15:20:36 -07002772 cifs_buf_release(pSMB);
2773
2774 /* Note: On -EAGAIN error only caller can retry on handle based calls
2775 since file handle passed in no longer valid */
2776
2777 return rc;
2778}
2779
2780int
Steve French96daf2b2011-05-27 04:34:02 +00002781CIFSSMBCopy(const int xid, struct cifs_tcon *tcon, const char *fromName,
Steve French50c2f752007-07-13 00:33:32 +00002782 const __u16 target_tid, const char *toName, const int flags,
2783 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002784{
2785 int rc = 0;
2786 COPY_REQ *pSMB = NULL;
2787 COPY_RSP *pSMBr = NULL;
2788 int bytes_returned;
2789 int name_len, name_len2;
2790 __u16 count;
2791
Joe Perchesb6b38f72010-04-21 03:50:45 +00002792 cFYI(1, "In CIFSSMBCopy");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002793copyRetry:
2794 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2795 (void **) &pSMBr);
2796 if (rc)
2797 return rc;
2798
2799 pSMB->BufferFormat = 0x04;
2800 pSMB->Tid2 = target_tid;
2801
2802 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2803
2804 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002805 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2806 fromName, PATH_MAX, nls_codepage,
2807 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002808 name_len++; /* trailing null */
2809 name_len *= 2;
2810 pSMB->OldFileName[name_len] = 0x04; /* pad */
2811 /* protocol requires ASCII signature byte on Unicode string */
2812 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002813 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002814 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2815 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002816 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2817 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002818 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002819 name_len = strnlen(fromName, PATH_MAX);
2820 name_len++; /* trailing null */
2821 strncpy(pSMB->OldFileName, fromName, name_len);
2822 name_len2 = strnlen(toName, PATH_MAX);
2823 name_len2++; /* trailing null */
2824 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2825 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2826 name_len2++; /* trailing null */
2827 name_len2++; /* signature byte */
2828 }
2829
2830 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002831 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832 pSMB->ByteCount = cpu_to_le16(count);
2833
2834 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2835 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2836 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002837 cFYI(1, "Send error in copy = %d with %d files copied",
2838 rc, le16_to_cpu(pSMBr->CopyCount));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002839 }
Steve French0d817bc2008-05-22 02:02:03 +00002840 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002841
2842 if (rc == -EAGAIN)
2843 goto copyRetry;
2844
2845 return rc;
2846}
2847
2848int
Steve French96daf2b2011-05-27 04:34:02 +00002849CIFSUnixCreateSymLink(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002850 const char *fromName, const char *toName,
2851 const struct nls_table *nls_codepage)
2852{
2853 TRANSACTION2_SPI_REQ *pSMB = NULL;
2854 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2855 char *data_offset;
2856 int name_len;
2857 int name_len_target;
2858 int rc = 0;
2859 int bytes_returned = 0;
2860 __u16 params, param_offset, offset, byte_count;
2861
Joe Perchesb6b38f72010-04-21 03:50:45 +00002862 cFYI(1, "In Symlink Unix style");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002863createSymLinkRetry:
2864 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2865 (void **) &pSMBr);
2866 if (rc)
2867 return rc;
2868
2869 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2870 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06002871 cifs_strtoUTF16((__le16 *) pSMB->FileName, fromName,
2872 /* find define for this maxpathcomponent */
2873 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002874 name_len++; /* trailing null */
2875 name_len *= 2;
2876
Steve French50c2f752007-07-13 00:33:32 +00002877 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002878 name_len = strnlen(fromName, PATH_MAX);
2879 name_len++; /* trailing null */
2880 strncpy(pSMB->FileName, fromName, name_len);
2881 }
2882 params = 6 + name_len;
2883 pSMB->MaxSetupCount = 0;
2884 pSMB->Reserved = 0;
2885 pSMB->Flags = 0;
2886 pSMB->Timeout = 0;
2887 pSMB->Reserved2 = 0;
2888 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002889 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002890 offset = param_offset + params;
2891
2892 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2893 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2894 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06002895 cifs_strtoUTF16((__le16 *) data_offset, toName, PATH_MAX
2896 /* find define for this maxpathcomponent */
2897 , nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002898 name_len_target++; /* trailing null */
2899 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002900 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002901 name_len_target = strnlen(toName, PATH_MAX);
2902 name_len_target++; /* trailing null */
2903 strncpy(data_offset, toName, name_len_target);
2904 }
2905
2906 pSMB->MaxParameterCount = cpu_to_le16(2);
2907 /* BB find exact max on data count below from sess */
2908 pSMB->MaxDataCount = cpu_to_le16(1000);
2909 pSMB->SetupCount = 1;
2910 pSMB->Reserved3 = 0;
2911 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2912 byte_count = 3 /* pad */ + params + name_len_target;
2913 pSMB->DataCount = cpu_to_le16(name_len_target);
2914 pSMB->ParameterCount = cpu_to_le16(params);
2915 pSMB->TotalDataCount = pSMB->DataCount;
2916 pSMB->TotalParameterCount = pSMB->ParameterCount;
2917 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2918 pSMB->DataOffset = cpu_to_le16(offset);
2919 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2920 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002921 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002922 pSMB->ByteCount = cpu_to_le16(byte_count);
2923 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2924 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002925 cifs_stats_inc(&tcon->num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002926 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002927 cFYI(1, "Send error in SetPathInfo create symlink = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002928
Steve French0d817bc2008-05-22 02:02:03 +00002929 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002930
2931 if (rc == -EAGAIN)
2932 goto createSymLinkRetry;
2933
2934 return rc;
2935}
2936
2937int
Steve French96daf2b2011-05-27 04:34:02 +00002938CIFSUnixCreateHardLink(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002939 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002940 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002941{
2942 TRANSACTION2_SPI_REQ *pSMB = NULL;
2943 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2944 char *data_offset;
2945 int name_len;
2946 int name_len_target;
2947 int rc = 0;
2948 int bytes_returned = 0;
2949 __u16 params, param_offset, offset, byte_count;
2950
Joe Perchesb6b38f72010-04-21 03:50:45 +00002951 cFYI(1, "In Create Hard link Unix style");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002952createHardLinkRetry:
2953 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2954 (void **) &pSMBr);
2955 if (rc)
2956 return rc;
2957
2958 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002959 name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, toName,
2960 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002961 name_len++; /* trailing null */
2962 name_len *= 2;
2963
Steve French50c2f752007-07-13 00:33:32 +00002964 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002965 name_len = strnlen(toName, PATH_MAX);
2966 name_len++; /* trailing null */
2967 strncpy(pSMB->FileName, toName, name_len);
2968 }
2969 params = 6 + name_len;
2970 pSMB->MaxSetupCount = 0;
2971 pSMB->Reserved = 0;
2972 pSMB->Flags = 0;
2973 pSMB->Timeout = 0;
2974 pSMB->Reserved2 = 0;
2975 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002976 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002977 offset = param_offset + params;
2978
2979 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2980 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2981 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06002982 cifsConvertToUTF16((__le16 *) data_offset, fromName,
2983 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002984 name_len_target++; /* trailing null */
2985 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002986 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002987 name_len_target = strnlen(fromName, PATH_MAX);
2988 name_len_target++; /* trailing null */
2989 strncpy(data_offset, fromName, name_len_target);
2990 }
2991
2992 pSMB->MaxParameterCount = cpu_to_le16(2);
2993 /* BB find exact max on data count below from sess*/
2994 pSMB->MaxDataCount = cpu_to_le16(1000);
2995 pSMB->SetupCount = 1;
2996 pSMB->Reserved3 = 0;
2997 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2998 byte_count = 3 /* pad */ + params + name_len_target;
2999 pSMB->ParameterCount = cpu_to_le16(params);
3000 pSMB->TotalParameterCount = pSMB->ParameterCount;
3001 pSMB->DataCount = cpu_to_le16(name_len_target);
3002 pSMB->TotalDataCount = pSMB->DataCount;
3003 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3004 pSMB->DataOffset = cpu_to_le16(offset);
3005 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
3006 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003007 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003008 pSMB->ByteCount = cpu_to_le16(byte_count);
3009 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3010 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003011 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00003012 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003013 cFYI(1, "Send error in SetPathInfo (hard link) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003014
3015 cifs_buf_release(pSMB);
3016 if (rc == -EAGAIN)
3017 goto createHardLinkRetry;
3018
3019 return rc;
3020}
3021
3022int
Steve French96daf2b2011-05-27 04:34:02 +00003023CIFSCreateHardLink(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003024 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07003025 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003026{
3027 int rc = 0;
3028 NT_RENAME_REQ *pSMB = NULL;
3029 RENAME_RSP *pSMBr = NULL;
3030 int bytes_returned;
3031 int name_len, name_len2;
3032 __u16 count;
3033
Joe Perchesb6b38f72010-04-21 03:50:45 +00003034 cFYI(1, "In CIFSCreateHardLink");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003035winCreateHardLinkRetry:
3036
3037 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
3038 (void **) &pSMBr);
3039 if (rc)
3040 return rc;
3041
3042 pSMB->SearchAttributes =
3043 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3044 ATTR_DIRECTORY);
3045 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
3046 pSMB->ClusterCount = 0;
3047
3048 pSMB->BufferFormat = 0x04;
3049
3050 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3051 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003052 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, fromName,
3053 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003054 name_len++; /* trailing null */
3055 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05003056
3057 /* protocol specifies ASCII buffer format (0x04) for unicode */
3058 pSMB->OldFileName[name_len] = 0x04;
3059 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003060 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06003061 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
3062 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003063 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
3064 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00003065 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003066 name_len = strnlen(fromName, PATH_MAX);
3067 name_len++; /* trailing null */
3068 strncpy(pSMB->OldFileName, fromName, name_len);
3069 name_len2 = strnlen(toName, PATH_MAX);
3070 name_len2++; /* trailing null */
3071 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
3072 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
3073 name_len2++; /* trailing null */
3074 name_len2++; /* signature byte */
3075 }
3076
3077 count = 1 /* string type byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003078 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003079 pSMB->ByteCount = cpu_to_le16(count);
3080
3081 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3082 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003083 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00003084 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003085 cFYI(1, "Send error in hard link (NT rename) = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00003086
Linus Torvalds1da177e2005-04-16 15:20:36 -07003087 cifs_buf_release(pSMB);
3088 if (rc == -EAGAIN)
3089 goto winCreateHardLinkRetry;
3090
3091 return rc;
3092}
3093
3094int
Steve French96daf2b2011-05-27 04:34:02 +00003095CIFSSMBUnixQuerySymLink(const int xid, struct cifs_tcon *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04003096 const unsigned char *searchName, char **symlinkinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003097 const struct nls_table *nls_codepage)
3098{
3099/* SMB_QUERY_FILE_UNIX_LINK */
3100 TRANSACTION2_QPI_REQ *pSMB = NULL;
3101 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3102 int rc = 0;
3103 int bytes_returned;
3104 int name_len;
3105 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04003106 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003107
Joe Perchesb6b38f72010-04-21 03:50:45 +00003108 cFYI(1, "In QPathSymLinkInfo (Unix) for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003109
3110querySymLinkRetry:
3111 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3112 (void **) &pSMBr);
3113 if (rc)
3114 return rc;
3115
3116 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3117 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003118 cifs_strtoUTF16((__le16 *) pSMB->FileName, searchName,
3119 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003120 name_len++; /* trailing null */
3121 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003122 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003123 name_len = strnlen(searchName, PATH_MAX);
3124 name_len++; /* trailing null */
3125 strncpy(pSMB->FileName, searchName, name_len);
3126 }
3127
3128 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3129 pSMB->TotalDataCount = 0;
3130 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04003131 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003132 pSMB->MaxSetupCount = 0;
3133 pSMB->Reserved = 0;
3134 pSMB->Flags = 0;
3135 pSMB->Timeout = 0;
3136 pSMB->Reserved2 = 0;
3137 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003138 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003139 pSMB->DataCount = 0;
3140 pSMB->DataOffset = 0;
3141 pSMB->SetupCount = 1;
3142 pSMB->Reserved3 = 0;
3143 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3144 byte_count = params + 1 /* pad */ ;
3145 pSMB->TotalParameterCount = cpu_to_le16(params);
3146 pSMB->ParameterCount = pSMB->TotalParameterCount;
3147 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
3148 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003149 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003150 pSMB->ByteCount = cpu_to_le16(byte_count);
3151
3152 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3153 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3154 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003155 cFYI(1, "Send error in QuerySymLinkInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003156 } else {
3157 /* decode response */
3158
3159 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003160 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003161 if (rc || get_bcc(&pSMBr->hdr) < 2)
Jeff Layton460b9692009-04-30 07:17:56 -04003162 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003163 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00003164 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04003165 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003166
Jeff Layton460b9692009-04-30 07:17:56 -04003167 data_start = ((char *) &pSMBr->hdr.Protocol) +
3168 le16_to_cpu(pSMBr->t2.DataOffset);
3169
Steve French0e0d2cf2009-05-01 05:27:32 +00003170 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3171 is_unicode = true;
3172 else
3173 is_unicode = false;
3174
Steve French737b7582005-04-28 22:41:06 -07003175 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchacbbb762012-01-18 22:32:33 -06003176 *symlinkinfo = cifs_strndup_from_utf16(data_start,
3177 count, is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04003178 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04003179 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003180 }
3181 }
3182 cifs_buf_release(pSMB);
3183 if (rc == -EAGAIN)
3184 goto querySymLinkRetry;
3185 return rc;
3186}
3187
Steve Frenchc52a95542011-02-24 06:16:22 +00003188#ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL
3189/*
3190 * Recent Windows versions now create symlinks more frequently
3191 * and they use the "reparse point" mechanism below. We can of course
3192 * do symlinks nicely to Samba and other servers which support the
3193 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
3194 * "MF" symlinks optionally, but for recent Windows we really need to
3195 * reenable the code below and fix the cifs_symlink callers to handle this.
3196 * In the interim this code has been moved to its own config option so
3197 * it is not compiled in by default until callers fixed up and more tested.
3198 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003199int
Steve French96daf2b2011-05-27 04:34:02 +00003200CIFSSMBQueryReparseLinkInfo(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003201 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00003202 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003203 const struct nls_table *nls_codepage)
3204{
3205 int rc = 0;
3206 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00003207 struct smb_com_transaction_ioctl_req *pSMB;
3208 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003209
Joe Perchesb6b38f72010-04-21 03:50:45 +00003210 cFYI(1, "In Windows reparse style QueryLink for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003211 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3212 (void **) &pSMBr);
3213 if (rc)
3214 return rc;
3215
3216 pSMB->TotalParameterCount = 0 ;
3217 pSMB->TotalDataCount = 0;
3218 pSMB->MaxParameterCount = cpu_to_le32(2);
3219 /* BB find exact data count max from sess structure BB */
Jeff Laytonc974bef2011-10-11 06:41:32 -04003220 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003221 pSMB->MaxSetupCount = 4;
3222 pSMB->Reserved = 0;
3223 pSMB->ParameterOffset = 0;
3224 pSMB->DataCount = 0;
3225 pSMB->DataOffset = 0;
3226 pSMB->SetupCount = 4;
3227 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
3228 pSMB->ParameterCount = pSMB->TotalParameterCount;
3229 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
3230 pSMB->IsFsctl = 1; /* FSCTL */
3231 pSMB->IsRootFlag = 0;
3232 pSMB->Fid = fid; /* file handle always le */
3233 pSMB->ByteCount = 0;
3234
3235 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3236 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3237 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003238 cFYI(1, "Send error in QueryReparseLinkInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003239 } else { /* decode response */
3240 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
3241 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
Jeff Layton820a8032011-05-04 08:05:26 -04003242 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
3243 /* BB also check enough total bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003244 rc = -EIO; /* bad smb */
Steve Frenchafe48c32009-05-02 05:25:46 +00003245 goto qreparse_out;
3246 }
3247 if (data_count && (data_count < 2048)) {
3248 char *end_of_smb = 2 /* sizeof byte count */ +
Jeff Layton820a8032011-05-04 08:05:26 -04003249 get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003250
Steve Frenchafe48c32009-05-02 05:25:46 +00003251 struct reparse_data *reparse_buf =
Steve French50c2f752007-07-13 00:33:32 +00003252 (struct reparse_data *)
3253 ((char *)&pSMBr->hdr.Protocol
3254 + data_offset);
Steve Frenchafe48c32009-05-02 05:25:46 +00003255 if ((char *)reparse_buf >= end_of_smb) {
3256 rc = -EIO;
3257 goto qreparse_out;
3258 }
3259 if ((reparse_buf->LinkNamesBuf +
3260 reparse_buf->TargetNameOffset +
3261 reparse_buf->TargetNameLen) > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003262 cFYI(1, "reparse buf beyond SMB");
Steve Frenchafe48c32009-05-02 05:25:46 +00003263 rc = -EIO;
3264 goto qreparse_out;
3265 }
Steve French50c2f752007-07-13 00:33:32 +00003266
Steve Frenchafe48c32009-05-02 05:25:46 +00003267 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3268 cifs_from_ucs2(symlinkinfo, (__le16 *)
Steve French50c2f752007-07-13 00:33:32 +00003269 (reparse_buf->LinkNamesBuf +
3270 reparse_buf->TargetNameOffset),
Steve Frenchafe48c32009-05-02 05:25:46 +00003271 buflen,
3272 reparse_buf->TargetNameLen,
3273 nls_codepage, 0);
3274 } else { /* ASCII names */
3275 strncpy(symlinkinfo,
3276 reparse_buf->LinkNamesBuf +
3277 reparse_buf->TargetNameOffset,
3278 min_t(const int, buflen,
3279 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003280 }
Steve Frenchafe48c32009-05-02 05:25:46 +00003281 } else {
3282 rc = -EIO;
Joe Perchesb6b38f72010-04-21 03:50:45 +00003283 cFYI(1, "Invalid return data count on "
3284 "get reparse info ioctl");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003285 }
Steve Frenchafe48c32009-05-02 05:25:46 +00003286 symlinkinfo[buflen] = 0; /* just in case so the caller
3287 does not go off the end of the buffer */
Joe Perchesb6b38f72010-04-21 03:50:45 +00003288 cFYI(1, "readlink result - %s", symlinkinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003289 }
Steve French989c7e52009-05-02 05:32:20 +00003290
Linus Torvalds1da177e2005-04-16 15:20:36 -07003291qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07003292 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003293
3294 /* Note: On -EAGAIN error only caller can retry on handle based calls
3295 since file handle passed in no longer valid */
3296
3297 return rc;
3298}
Steve Frenchc52a95542011-02-24 06:16:22 +00003299#endif /* CIFS_SYMLINK_EXPERIMENTAL */ /* BB temporarily unused */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003300
3301#ifdef CONFIG_CIFS_POSIX
3302
3303/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00003304static void cifs_convert_ace(posix_acl_xattr_entry *ace,
3305 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003306{
3307 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08003308 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
3309 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
3310 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesb6b38f72010-04-21 03:50:45 +00003311 /* cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003312
3313 return;
3314}
3315
3316/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00003317static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
3318 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003319{
3320 int size = 0;
3321 int i;
3322 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00003323 struct cifs_posix_ace *pACE;
3324 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
3325 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003326
3327 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
3328 return -EOPNOTSUPP;
3329
Steve French790fe572007-07-07 19:25:05 +00003330 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003331 count = le16_to_cpu(cifs_acl->access_entry_count);
3332 pACE = &cifs_acl->ace_array[0];
3333 size = sizeof(struct cifs_posix_acl);
3334 size += sizeof(struct cifs_posix_ace) * count;
3335 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003336 if (size_of_data_area < size) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003337 cFYI(1, "bad CIFS POSIX ACL size %d vs. %d",
3338 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003339 return -EINVAL;
3340 }
Steve French790fe572007-07-07 19:25:05 +00003341 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003342 count = le16_to_cpu(cifs_acl->access_entry_count);
3343 size = sizeof(struct cifs_posix_acl);
3344 size += sizeof(struct cifs_posix_ace) * count;
3345/* skip past access ACEs to get to default ACEs */
3346 pACE = &cifs_acl->ace_array[count];
3347 count = le16_to_cpu(cifs_acl->default_entry_count);
3348 size += sizeof(struct cifs_posix_ace) * count;
3349 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003350 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003351 return -EINVAL;
3352 } else {
3353 /* illegal type */
3354 return -EINVAL;
3355 }
3356
3357 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00003358 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00003359 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00003360 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003361 return -ERANGE;
3362 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08003363 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00003364 for (i = 0; i < count ; i++) {
3365 cifs_convert_ace(&local_acl->a_entries[i], pACE);
3366 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003367 }
3368 }
3369 return size;
3370}
3371
Steve French50c2f752007-07-13 00:33:32 +00003372static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
3373 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003374{
3375 __u16 rc = 0; /* 0 = ACL converted ok */
3376
Steve Frenchff7feac2005-11-15 16:45:16 -08003377 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
3378 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003379 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00003380 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003381 /* Probably no need to le convert -1 on any arch but can not hurt */
3382 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00003383 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08003384 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesb6b38f72010-04-21 03:50:45 +00003385 /*cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id);*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003386 return rc;
3387}
3388
3389/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00003390static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
3391 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003392{
3393 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00003394 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
3395 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003396 int count;
3397 int i;
3398
Steve French790fe572007-07-07 19:25:05 +00003399 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003400 return 0;
3401
3402 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesb6b38f72010-04-21 03:50:45 +00003403 cFYI(1, "setting acl with %d entries from buf of length %d and "
Steve French63135e02007-07-17 17:34:02 +00003404 "version of %d",
Joe Perchesb6b38f72010-04-21 03:50:45 +00003405 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00003406 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003407 cFYI(1, "unknown POSIX ACL version %d",
3408 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003409 return 0;
3410 }
3411 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00003412 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08003413 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00003414 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08003415 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003416 else {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003417 cFYI(1, "unknown ACL type %d", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003418 return 0;
3419 }
Steve French50c2f752007-07-13 00:33:32 +00003420 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003421 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
3422 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00003423 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003424 /* ACE not converted */
3425 break;
3426 }
3427 }
Steve French790fe572007-07-07 19:25:05 +00003428 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003429 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
3430 rc += sizeof(struct cifs_posix_acl);
3431 /* BB add check to make sure ACL does not overflow SMB */
3432 }
3433 return rc;
3434}
3435
3436int
Steve French96daf2b2011-05-27 04:34:02 +00003437CIFSSMBGetPosixACL(const int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003438 const unsigned char *searchName,
3439 char *acl_inf, const int buflen, const int acl_type,
3440 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003441{
3442/* SMB_QUERY_POSIX_ACL */
3443 TRANSACTION2_QPI_REQ *pSMB = NULL;
3444 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3445 int rc = 0;
3446 int bytes_returned;
3447 int name_len;
3448 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00003449
Joe Perchesb6b38f72010-04-21 03:50:45 +00003450 cFYI(1, "In GetPosixACL (Unix) for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003451
3452queryAclRetry:
3453 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3454 (void **) &pSMBr);
3455 if (rc)
3456 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003457
Linus Torvalds1da177e2005-04-16 15:20:36 -07003458 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3459 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003460 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3461 searchName, PATH_MAX, nls_codepage,
3462 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003463 name_len++; /* trailing null */
3464 name_len *= 2;
3465 pSMB->FileName[name_len] = 0;
3466 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00003467 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003468 name_len = strnlen(searchName, PATH_MAX);
3469 name_len++; /* trailing null */
3470 strncpy(pSMB->FileName, searchName, name_len);
3471 }
3472
3473 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3474 pSMB->TotalDataCount = 0;
3475 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00003476 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003477 pSMB->MaxDataCount = cpu_to_le16(4000);
3478 pSMB->MaxSetupCount = 0;
3479 pSMB->Reserved = 0;
3480 pSMB->Flags = 0;
3481 pSMB->Timeout = 0;
3482 pSMB->Reserved2 = 0;
3483 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003484 offsetof(struct smb_com_transaction2_qpi_req,
3485 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003486 pSMB->DataCount = 0;
3487 pSMB->DataOffset = 0;
3488 pSMB->SetupCount = 1;
3489 pSMB->Reserved3 = 0;
3490 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3491 byte_count = params + 1 /* pad */ ;
3492 pSMB->TotalParameterCount = cpu_to_le16(params);
3493 pSMB->ParameterCount = pSMB->TotalParameterCount;
3494 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
3495 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003496 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003497 pSMB->ByteCount = cpu_to_le16(byte_count);
3498
3499 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3500 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08003501 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003502 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003503 cFYI(1, "Send error in Query POSIX ACL = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003504 } else {
3505 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00003506
Linus Torvalds1da177e2005-04-16 15:20:36 -07003507 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003508 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003509 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003510 rc = -EIO; /* bad smb */
3511 else {
3512 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3513 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3514 rc = cifs_copy_posix_acl(acl_inf,
3515 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00003516 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003517 }
3518 }
3519 cifs_buf_release(pSMB);
3520 if (rc == -EAGAIN)
3521 goto queryAclRetry;
3522 return rc;
3523}
3524
3525int
Steve French96daf2b2011-05-27 04:34:02 +00003526CIFSSMBSetPosixACL(const int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003527 const unsigned char *fileName,
3528 const char *local_acl, const int buflen,
3529 const int acl_type,
3530 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003531{
3532 struct smb_com_transaction2_spi_req *pSMB = NULL;
3533 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3534 char *parm_data;
3535 int name_len;
3536 int rc = 0;
3537 int bytes_returned = 0;
3538 __u16 params, byte_count, data_count, param_offset, offset;
3539
Joe Perchesb6b38f72010-04-21 03:50:45 +00003540 cFYI(1, "In SetPosixACL (Unix) for path %s", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003541setAclRetry:
3542 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003543 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003544 if (rc)
3545 return rc;
3546 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3547 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003548 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
3549 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003550 name_len++; /* trailing null */
3551 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003552 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003553 name_len = strnlen(fileName, PATH_MAX);
3554 name_len++; /* trailing null */
3555 strncpy(pSMB->FileName, fileName, name_len);
3556 }
3557 params = 6 + name_len;
3558 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003559 /* BB find max SMB size from sess */
3560 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003561 pSMB->MaxSetupCount = 0;
3562 pSMB->Reserved = 0;
3563 pSMB->Flags = 0;
3564 pSMB->Timeout = 0;
3565 pSMB->Reserved2 = 0;
3566 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003567 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003568 offset = param_offset + params;
3569 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
3570 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3571
3572 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00003573 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003574
Steve French790fe572007-07-07 19:25:05 +00003575 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003576 rc = -EOPNOTSUPP;
3577 goto setACLerrorExit;
3578 }
3579 pSMB->DataOffset = cpu_to_le16(offset);
3580 pSMB->SetupCount = 1;
3581 pSMB->Reserved3 = 0;
3582 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3583 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
3584 byte_count = 3 /* pad */ + params + data_count;
3585 pSMB->DataCount = cpu_to_le16(data_count);
3586 pSMB->TotalDataCount = pSMB->DataCount;
3587 pSMB->ParameterCount = cpu_to_le16(params);
3588 pSMB->TotalParameterCount = pSMB->ParameterCount;
3589 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003590 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003591 pSMB->ByteCount = cpu_to_le16(byte_count);
3592 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003593 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003594 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003595 cFYI(1, "Set POSIX ACL returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003596
3597setACLerrorExit:
3598 cifs_buf_release(pSMB);
3599 if (rc == -EAGAIN)
3600 goto setAclRetry;
3601 return rc;
3602}
3603
Steve Frenchf654bac2005-04-28 22:41:04 -07003604/* BB fix tabs in this function FIXME BB */
3605int
Steve French96daf2b2011-05-27 04:34:02 +00003606CIFSGetExtAttr(const int xid, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00003607 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07003608{
Steve French50c2f752007-07-13 00:33:32 +00003609 int rc = 0;
3610 struct smb_t2_qfi_req *pSMB = NULL;
3611 struct smb_t2_qfi_rsp *pSMBr = NULL;
3612 int bytes_returned;
3613 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07003614
Joe Perchesb6b38f72010-04-21 03:50:45 +00003615 cFYI(1, "In GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00003616 if (tcon == NULL)
3617 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07003618
3619GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003620 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3621 (void **) &pSMBr);
3622 if (rc)
3623 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003624
Steve Frenchad7a2922008-02-07 23:25:02 +00003625 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003626 pSMB->t2.TotalDataCount = 0;
3627 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3628 /* BB find exact max data count below from sess structure BB */
3629 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3630 pSMB->t2.MaxSetupCount = 0;
3631 pSMB->t2.Reserved = 0;
3632 pSMB->t2.Flags = 0;
3633 pSMB->t2.Timeout = 0;
3634 pSMB->t2.Reserved2 = 0;
3635 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3636 Fid) - 4);
3637 pSMB->t2.DataCount = 0;
3638 pSMB->t2.DataOffset = 0;
3639 pSMB->t2.SetupCount = 1;
3640 pSMB->t2.Reserved3 = 0;
3641 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3642 byte_count = params + 1 /* pad */ ;
3643 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3644 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3645 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3646 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003647 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003648 inc_rfc1001_len(pSMB, byte_count);
Steve French790fe572007-07-07 19:25:05 +00003649 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003650
Steve French790fe572007-07-07 19:25:05 +00003651 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3652 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3653 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003654 cFYI(1, "error %d in GetExtAttr", rc);
Steve French790fe572007-07-07 19:25:05 +00003655 } else {
3656 /* decode response */
3657 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003658 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003659 if (rc || get_bcc(&pSMBr->hdr) < 2)
Steve French790fe572007-07-07 19:25:05 +00003660 /* If rc should we check for EOPNOSUPP and
3661 disable the srvino flag? or in caller? */
3662 rc = -EIO; /* bad smb */
3663 else {
3664 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3665 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3666 struct file_chattr_info *pfinfo;
3667 /* BB Do we need a cast or hash here ? */
3668 if (count != 16) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003669 cFYI(1, "Illegal size ret in GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00003670 rc = -EIO;
3671 goto GetExtAttrOut;
3672 }
3673 pfinfo = (struct file_chattr_info *)
3674 (data_offset + (char *) &pSMBr->hdr.Protocol);
3675 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003676 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003677 }
3678 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003679GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003680 cifs_buf_release(pSMB);
3681 if (rc == -EAGAIN)
3682 goto GetExtAttrRetry;
3683 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003684}
3685
Steve Frenchf654bac2005-04-28 22:41:04 -07003686#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003687
Jeff Layton79df1ba2010-12-06 12:52:08 -05003688#ifdef CONFIG_CIFS_ACL
3689/*
3690 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3691 * all NT TRANSACTS that we init here have total parm and data under about 400
3692 * bytes (to fit in small cifs buffer size), which is the case so far, it
3693 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3694 * returned setup area) and MaxParameterCount (returned parms size) must be set
3695 * by caller
3696 */
3697static int
3698smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French96daf2b2011-05-27 04:34:02 +00003699 const int parm_len, struct cifs_tcon *tcon,
Jeff Layton79df1ba2010-12-06 12:52:08 -05003700 void **ret_buf)
3701{
3702 int rc;
3703 __u32 temp_offset;
3704 struct smb_com_ntransact_req *pSMB;
3705
3706 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3707 (void **)&pSMB);
3708 if (rc)
3709 return rc;
3710 *ret_buf = (void *)pSMB;
3711 pSMB->Reserved = 0;
3712 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3713 pSMB->TotalDataCount = 0;
Jeff Laytonc974bef2011-10-11 06:41:32 -04003714 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003715 pSMB->ParameterCount = pSMB->TotalParameterCount;
3716 pSMB->DataCount = pSMB->TotalDataCount;
3717 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3718 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3719 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3720 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3721 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3722 pSMB->SubCommand = cpu_to_le16(sub_command);
3723 return 0;
3724}
3725
3726static int
3727validate_ntransact(char *buf, char **ppparm, char **ppdata,
3728 __u32 *pparmlen, __u32 *pdatalen)
3729{
3730 char *end_of_smb;
3731 __u32 data_count, data_offset, parm_count, parm_offset;
3732 struct smb_com_ntransact_rsp *pSMBr;
Jeff Layton820a8032011-05-04 08:05:26 -04003733 u16 bcc;
Jeff Layton79df1ba2010-12-06 12:52:08 -05003734
3735 *pdatalen = 0;
3736 *pparmlen = 0;
3737
3738 if (buf == NULL)
3739 return -EINVAL;
3740
3741 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3742
Jeff Layton820a8032011-05-04 08:05:26 -04003743 bcc = get_bcc(&pSMBr->hdr);
3744 end_of_smb = 2 /* sizeof byte count */ + bcc +
Jeff Layton79df1ba2010-12-06 12:52:08 -05003745 (char *)&pSMBr->ByteCount;
3746
3747 data_offset = le32_to_cpu(pSMBr->DataOffset);
3748 data_count = le32_to_cpu(pSMBr->DataCount);
3749 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3750 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3751
3752 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3753 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3754
3755 /* should we also check that parm and data areas do not overlap? */
3756 if (*ppparm > end_of_smb) {
3757 cFYI(1, "parms start after end of smb");
3758 return -EINVAL;
3759 } else if (parm_count + *ppparm > end_of_smb) {
3760 cFYI(1, "parm end after end of smb");
3761 return -EINVAL;
3762 } else if (*ppdata > end_of_smb) {
3763 cFYI(1, "data starts after end of smb");
3764 return -EINVAL;
3765 } else if (data_count + *ppdata > end_of_smb) {
3766 cFYI(1, "data %p + count %d (%p) past smb end %p start %p",
3767 *ppdata, data_count, (data_count + *ppdata),
3768 end_of_smb, pSMBr);
3769 return -EINVAL;
Jeff Layton820a8032011-05-04 08:05:26 -04003770 } else if (parm_count + data_count > bcc) {
Jeff Layton79df1ba2010-12-06 12:52:08 -05003771 cFYI(1, "parm count and data count larger than SMB");
3772 return -EINVAL;
3773 }
3774 *pdatalen = data_count;
3775 *pparmlen = parm_count;
3776 return 0;
3777}
3778
Steve French0a4b92c2006-01-12 15:44:21 -08003779/* Get Security Descriptor (by handle) from remote server for a file or dir */
3780int
Steve French96daf2b2011-05-27 04:34:02 +00003781CIFSSMBGetCIFSACL(const int xid, struct cifs_tcon *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003782 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003783{
3784 int rc = 0;
3785 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003786 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003787 struct kvec iov[1];
3788
Joe Perchesb6b38f72010-04-21 03:50:45 +00003789 cFYI(1, "GetCifsACL");
Steve French0a4b92c2006-01-12 15:44:21 -08003790
Steve French630f3f0c2007-10-25 21:17:17 +00003791 *pbuflen = 0;
3792 *acl_inf = NULL;
3793
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003794 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003795 8 /* parm len */, tcon, (void **) &pSMB);
3796 if (rc)
3797 return rc;
3798
3799 pSMB->MaxParameterCount = cpu_to_le32(4);
3800 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3801 pSMB->MaxSetupCount = 0;
3802 pSMB->Fid = fid; /* file handle always le */
3803 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3804 CIFS_ACL_DACL);
3805 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003806 inc_rfc1001_len(pSMB, 11);
Steve French0a4b92c2006-01-12 15:44:21 -08003807 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003808 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French0a4b92c2006-01-12 15:44:21 -08003809
Steve Frencha761ac52007-10-18 21:45:27 +00003810 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Jeff Layton77499812011-01-11 07:24:23 -05003811 0);
Steve French0a4b92c2006-01-12 15:44:21 -08003812 cifs_stats_inc(&tcon->num_acl_get);
3813 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003814 cFYI(1, "Send error in QuerySecDesc = %d", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08003815 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003816 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003817 __u32 parm_len;
3818 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003819 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003820 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003821
3822/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003823 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003824 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003825 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003826 goto qsec_out;
3827 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3828
Joe Perchesb6b38f72010-04-21 03:50:45 +00003829 cFYI(1, "smb %p parm %p data %p", pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08003830
3831 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3832 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003833 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003834 goto qsec_out;
3835 }
3836
3837/* BB check that data area is minimum length and as big as acl_len */
3838
Steve Frenchaf6f4612007-10-16 18:40:37 +00003839 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003840 if (acl_len != *pbuflen) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003841 cERROR(1, "acl length %d does not match %d",
3842 acl_len, *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003843 if (*pbuflen > acl_len)
3844 *pbuflen = acl_len;
3845 }
Steve French0a4b92c2006-01-12 15:44:21 -08003846
Steve French630f3f0c2007-10-25 21:17:17 +00003847 /* check if buffer is big enough for the acl
3848 header followed by the smallest SID */
3849 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3850 (*pbuflen >= 64 * 1024)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003851 cERROR(1, "bad acl length %d", *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003852 rc = -EINVAL;
3853 *pbuflen = 0;
3854 } else {
3855 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3856 if (*acl_inf == NULL) {
3857 *pbuflen = 0;
3858 rc = -ENOMEM;
3859 }
3860 memcpy(*acl_inf, pdata, *pbuflen);
3861 }
Steve French0a4b92c2006-01-12 15:44:21 -08003862 }
3863qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003864 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003865 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003866 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003867 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003868/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003869 return rc;
3870}
Steve French97837582007-12-31 07:47:21 +00003871
3872int
Steve French96daf2b2011-05-27 04:34:02 +00003873CIFSSMBSetCIFSACL(const int xid, struct cifs_tcon *tcon, __u16 fid,
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003874 struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
Steve French97837582007-12-31 07:47:21 +00003875{
3876 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3877 int rc = 0;
3878 int bytes_returned = 0;
3879 SET_SEC_DESC_REQ *pSMB = NULL;
3880 NTRANSACT_RSP *pSMBr = NULL;
3881
3882setCifsAclRetry:
3883 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB,
3884 (void **) &pSMBr);
3885 if (rc)
3886 return (rc);
3887
3888 pSMB->MaxSetupCount = 0;
3889 pSMB->Reserved = 0;
3890
3891 param_count = 8;
3892 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3893 data_count = acllen;
3894 data_offset = param_offset + param_count;
3895 byte_count = 3 /* pad */ + param_count;
3896
3897 pSMB->DataCount = cpu_to_le32(data_count);
3898 pSMB->TotalDataCount = pSMB->DataCount;
3899 pSMB->MaxParameterCount = cpu_to_le32(4);
3900 pSMB->MaxDataCount = cpu_to_le32(16384);
3901 pSMB->ParameterCount = cpu_to_le32(param_count);
3902 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3903 pSMB->TotalParameterCount = pSMB->ParameterCount;
3904 pSMB->DataOffset = cpu_to_le32(data_offset);
3905 pSMB->SetupCount = 0;
3906 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3907 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3908
3909 pSMB->Fid = fid; /* file handle always le */
3910 pSMB->Reserved2 = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003911 pSMB->AclFlags = cpu_to_le32(aclflag);
Steve French97837582007-12-31 07:47:21 +00003912
3913 if (pntsd && acllen) {
3914 memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
3915 (char *) pntsd,
3916 acllen);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003917 inc_rfc1001_len(pSMB, byte_count + data_count);
Steve French97837582007-12-31 07:47:21 +00003918 } else
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003919 inc_rfc1001_len(pSMB, byte_count);
Steve French97837582007-12-31 07:47:21 +00003920
3921 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3922 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3923
Joe Perchesb6b38f72010-04-21 03:50:45 +00003924 cFYI(1, "SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00003925 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003926 cFYI(1, "Set CIFS ACL returned %d", rc);
Steve French97837582007-12-31 07:47:21 +00003927 cifs_buf_release(pSMB);
3928
3929 if (rc == -EAGAIN)
3930 goto setCifsAclRetry;
3931
3932 return (rc);
3933}
3934
Jeff Layton79df1ba2010-12-06 12:52:08 -05003935#endif /* CONFIG_CIFS_ACL */
Steve French0a4b92c2006-01-12 15:44:21 -08003936
Steve French6b8edfe2005-08-23 20:26:03 -07003937/* Legacy Query Path Information call for lookup to old servers such
3938 as Win9x/WinME */
Steve French96daf2b2011-05-27 04:34:02 +00003939int SMBQueryInformation(const int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003940 const unsigned char *searchName,
3941 FILE_ALL_INFO *pFinfo,
3942 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003943{
Steve Frenchad7a2922008-02-07 23:25:02 +00003944 QUERY_INFORMATION_REQ *pSMB;
3945 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003946 int rc = 0;
3947 int bytes_returned;
3948 int name_len;
3949
Joe Perchesb6b38f72010-04-21 03:50:45 +00003950 cFYI(1, "In SMBQPath path %s", searchName);
Steve French6b8edfe2005-08-23 20:26:03 -07003951QInfRetry:
3952 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003953 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003954 if (rc)
3955 return rc;
3956
3957 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3958 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003959 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3960 searchName, PATH_MAX, nls_codepage,
3961 remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003962 name_len++; /* trailing null */
3963 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003964 } else {
Steve French6b8edfe2005-08-23 20:26:03 -07003965 name_len = strnlen(searchName, PATH_MAX);
3966 name_len++; /* trailing null */
3967 strncpy(pSMB->FileName, searchName, name_len);
3968 }
3969 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003970 name_len++; /* account for buffer type byte */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003971 inc_rfc1001_len(pSMB, (__u16)name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07003972 pSMB->ByteCount = cpu_to_le16(name_len);
3973
3974 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003975 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003976 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003977 cFYI(1, "Send error in QueryInfo = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00003978 } else if (pFinfo) {
Steve French1bd5bbc2006-09-28 03:35:57 +00003979 struct timespec ts;
3980 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00003981
3982 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003983 /* BB FIXME - add time zone adjustment BB */
Steve French6b8edfe2005-08-23 20:26:03 -07003984 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003985 ts.tv_nsec = 0;
3986 ts.tv_sec = time;
3987 /* decode time fields */
Al Viro733f99a2006-10-14 16:48:26 +01003988 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
Steve French1bd5bbc2006-09-28 03:35:57 +00003989 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3990 pFinfo->LastAccessTime = 0;
Steve French70ca7342005-09-22 16:32:06 -07003991 pFinfo->AllocationSize =
3992 cpu_to_le64(le32_to_cpu(pSMBr->size));
3993 pFinfo->EndOfFile = pFinfo->AllocationSize;
3994 pFinfo->Attributes =
3995 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003996 } else
3997 rc = -EIO; /* bad buffer passed in */
3998
3999 cifs_buf_release(pSMB);
4000
4001 if (rc == -EAGAIN)
4002 goto QInfRetry;
4003
4004 return rc;
4005}
4006
Jeff Laytonbcd53572010-02-12 07:44:16 -05004007int
Steve French96daf2b2011-05-27 04:34:02 +00004008CIFSSMBQFileInfo(const int xid, struct cifs_tcon *tcon,
Jeff Laytonbcd53572010-02-12 07:44:16 -05004009 u16 netfid, FILE_ALL_INFO *pFindData)
4010{
4011 struct smb_t2_qfi_req *pSMB = NULL;
4012 struct smb_t2_qfi_rsp *pSMBr = NULL;
4013 int rc = 0;
4014 int bytes_returned;
4015 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07004016
Jeff Laytonbcd53572010-02-12 07:44:16 -05004017QFileInfoRetry:
4018 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4019 (void **) &pSMBr);
4020 if (rc)
4021 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07004022
Jeff Laytonbcd53572010-02-12 07:44:16 -05004023 params = 2 /* level */ + 2 /* fid */;
4024 pSMB->t2.TotalDataCount = 0;
4025 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4026 /* BB find exact max data count below from sess structure BB */
4027 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4028 pSMB->t2.MaxSetupCount = 0;
4029 pSMB->t2.Reserved = 0;
4030 pSMB->t2.Flags = 0;
4031 pSMB->t2.Timeout = 0;
4032 pSMB->t2.Reserved2 = 0;
4033 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4034 Fid) - 4);
4035 pSMB->t2.DataCount = 0;
4036 pSMB->t2.DataOffset = 0;
4037 pSMB->t2.SetupCount = 1;
4038 pSMB->t2.Reserved3 = 0;
4039 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4040 byte_count = params + 1 /* pad */ ;
4041 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4042 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4043 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
4044 pSMB->Pad = 0;
4045 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004046 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonbcd53572010-02-12 07:44:16 -05004047
4048 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4049 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4050 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00004051 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05004052 } else { /* decode response */
4053 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4054
4055 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4056 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004057 else if (get_bcc(&pSMBr->hdr) < 40)
Jeff Laytonbcd53572010-02-12 07:44:16 -05004058 rc = -EIO; /* bad smb */
4059 else if (pFindData) {
4060 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4061 memcpy((char *) pFindData,
4062 (char *) &pSMBr->hdr.Protocol +
4063 data_offset, sizeof(FILE_ALL_INFO));
4064 } else
4065 rc = -ENOMEM;
4066 }
4067 cifs_buf_release(pSMB);
4068 if (rc == -EAGAIN)
4069 goto QFileInfoRetry;
4070
4071 return rc;
4072}
Steve French6b8edfe2005-08-23 20:26:03 -07004073
Linus Torvalds1da177e2005-04-16 15:20:36 -07004074int
Steve French96daf2b2011-05-27 04:34:02 +00004075CIFSSMBQPathInfo(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004076 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00004077 FILE_ALL_INFO *pFindData,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004078 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07004079 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004080{
4081/* level 263 SMB_QUERY_FILE_ALL_INFO */
4082 TRANSACTION2_QPI_REQ *pSMB = NULL;
4083 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4084 int rc = 0;
4085 int bytes_returned;
4086 int name_len;
4087 __u16 params, byte_count;
4088
Joe Perchesb6b38f72010-04-21 03:50:45 +00004089/* cFYI(1, "In QPathInfo path %s", searchName); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004090QPathInfoRetry:
4091 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4092 (void **) &pSMBr);
4093 if (rc)
4094 return rc;
4095
4096 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4097 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004098 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4099 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004100 name_len++; /* trailing null */
4101 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004102 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004103 name_len = strnlen(searchName, PATH_MAX);
4104 name_len++; /* trailing null */
4105 strncpy(pSMB->FileName, searchName, name_len);
4106 }
4107
Steve French50c2f752007-07-13 00:33:32 +00004108 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004109 pSMB->TotalDataCount = 0;
4110 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004111 /* BB find exact max SMB PDU from sess structure BB */
4112 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004113 pSMB->MaxSetupCount = 0;
4114 pSMB->Reserved = 0;
4115 pSMB->Flags = 0;
4116 pSMB->Timeout = 0;
4117 pSMB->Reserved2 = 0;
4118 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004119 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004120 pSMB->DataCount = 0;
4121 pSMB->DataOffset = 0;
4122 pSMB->SetupCount = 1;
4123 pSMB->Reserved3 = 0;
4124 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4125 byte_count = params + 1 /* pad */ ;
4126 pSMB->TotalParameterCount = cpu_to_le16(params);
4127 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00004128 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004129 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
4130 else
4131 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004132 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004133 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004134 pSMB->ByteCount = cpu_to_le16(byte_count);
4135
4136 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4137 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4138 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004139 cFYI(1, "Send error in QPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004140 } else { /* decode response */
4141 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4142
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004143 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4144 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004145 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004146 rc = -EIO; /* bad smb */
Jeff Layton820a8032011-05-04 08:05:26 -04004147 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
Steve French50c2f752007-07-13 00:33:32 +00004148 rc = -EIO; /* 24 or 26 expected but we do not read
4149 last field */
4150 else if (pFindData) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004151 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004152 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00004153
4154 /* On legacy responses we do not read the last field,
4155 EAsize, fortunately since it varies by subdialect and
4156 also note it differs on Set vs. Get, ie two bytes or 4
4157 bytes depending but we don't care here */
4158 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004159 size = sizeof(FILE_INFO_STANDARD);
4160 else
4161 size = sizeof(FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004162 memcpy((char *) pFindData,
4163 (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004164 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004165 } else
4166 rc = -ENOMEM;
4167 }
4168 cifs_buf_release(pSMB);
4169 if (rc == -EAGAIN)
4170 goto QPathInfoRetry;
4171
4172 return rc;
4173}
4174
4175int
Steve French96daf2b2011-05-27 04:34:02 +00004176CIFSSMBUnixQFileInfo(const int xid, struct cifs_tcon *tcon,
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004177 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
4178{
4179 struct smb_t2_qfi_req *pSMB = NULL;
4180 struct smb_t2_qfi_rsp *pSMBr = NULL;
4181 int rc = 0;
4182 int bytes_returned;
4183 __u16 params, byte_count;
4184
4185UnixQFileInfoRetry:
4186 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4187 (void **) &pSMBr);
4188 if (rc)
4189 return rc;
4190
4191 params = 2 /* level */ + 2 /* fid */;
4192 pSMB->t2.TotalDataCount = 0;
4193 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4194 /* BB find exact max data count below from sess structure BB */
4195 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4196 pSMB->t2.MaxSetupCount = 0;
4197 pSMB->t2.Reserved = 0;
4198 pSMB->t2.Flags = 0;
4199 pSMB->t2.Timeout = 0;
4200 pSMB->t2.Reserved2 = 0;
4201 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4202 Fid) - 4);
4203 pSMB->t2.DataCount = 0;
4204 pSMB->t2.DataOffset = 0;
4205 pSMB->t2.SetupCount = 1;
4206 pSMB->t2.Reserved3 = 0;
4207 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4208 byte_count = params + 1 /* pad */ ;
4209 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4210 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4211 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4212 pSMB->Pad = 0;
4213 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004214 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004215
4216 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4217 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4218 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00004219 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004220 } else { /* decode response */
4221 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4222
Jeff Layton820a8032011-05-04 08:05:26 -04004223 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Steve Frenchf19159d2010-04-21 04:12:10 +00004224 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response.\n"
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004225 "Unix Extensions can be disabled on mount "
Steve Frenchf19159d2010-04-21 04:12:10 +00004226 "by specifying the nosfu mount option.");
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004227 rc = -EIO; /* bad smb */
4228 } else {
4229 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4230 memcpy((char *) pFindData,
4231 (char *) &pSMBr->hdr.Protocol +
4232 data_offset,
4233 sizeof(FILE_UNIX_BASIC_INFO));
4234 }
4235 }
4236
4237 cifs_buf_release(pSMB);
4238 if (rc == -EAGAIN)
4239 goto UnixQFileInfoRetry;
4240
4241 return rc;
4242}
4243
4244int
Steve French96daf2b2011-05-27 04:34:02 +00004245CIFSSMBUnixQPathInfo(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004246 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00004247 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07004248 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004249{
4250/* SMB_QUERY_FILE_UNIX_BASIC */
4251 TRANSACTION2_QPI_REQ *pSMB = NULL;
4252 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4253 int rc = 0;
4254 int bytes_returned = 0;
4255 int name_len;
4256 __u16 params, byte_count;
4257
Joe Perchesb6b38f72010-04-21 03:50:45 +00004258 cFYI(1, "In QPathInfo (Unix) the path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004259UnixQPathInfoRetry:
4260 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4261 (void **) &pSMBr);
4262 if (rc)
4263 return rc;
4264
4265 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4266 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004267 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4268 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004269 name_len++; /* trailing null */
4270 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004271 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004272 name_len = strnlen(searchName, PATH_MAX);
4273 name_len++; /* trailing null */
4274 strncpy(pSMB->FileName, searchName, name_len);
4275 }
4276
Steve French50c2f752007-07-13 00:33:32 +00004277 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004278 pSMB->TotalDataCount = 0;
4279 pSMB->MaxParameterCount = cpu_to_le16(2);
4280 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00004281 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004282 pSMB->MaxSetupCount = 0;
4283 pSMB->Reserved = 0;
4284 pSMB->Flags = 0;
4285 pSMB->Timeout = 0;
4286 pSMB->Reserved2 = 0;
4287 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004288 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004289 pSMB->DataCount = 0;
4290 pSMB->DataOffset = 0;
4291 pSMB->SetupCount = 1;
4292 pSMB->Reserved3 = 0;
4293 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4294 byte_count = params + 1 /* pad */ ;
4295 pSMB->TotalParameterCount = cpu_to_le16(params);
4296 pSMB->ParameterCount = pSMB->TotalParameterCount;
4297 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4298 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004299 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004300 pSMB->ByteCount = cpu_to_le16(byte_count);
4301
4302 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4303 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4304 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004305 cFYI(1, "Send error in QPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004306 } else { /* decode response */
4307 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4308
Jeff Layton820a8032011-05-04 08:05:26 -04004309 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004310 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response.\n"
Steve French1e71f252007-09-20 15:30:07 +00004311 "Unix Extensions can be disabled on mount "
Joe Perchesb6b38f72010-04-21 03:50:45 +00004312 "by specifying the nosfu mount option.");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004313 rc = -EIO; /* bad smb */
4314 } else {
4315 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4316 memcpy((char *) pFindData,
4317 (char *) &pSMBr->hdr.Protocol +
4318 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00004319 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004320 }
4321 }
4322 cifs_buf_release(pSMB);
4323 if (rc == -EAGAIN)
4324 goto UnixQPathInfoRetry;
4325
4326 return rc;
4327}
4328
Linus Torvalds1da177e2005-04-16 15:20:36 -07004329/* xid, tcon, searchName and codepage are input parms, rest are returned */
4330int
Steve French96daf2b2011-05-27 04:34:02 +00004331CIFSFindFirst(const int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004332 const char *searchName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004333 const struct nls_table *nls_codepage,
Steve French50c2f752007-07-13 00:33:32 +00004334 __u16 *pnetfid,
4335 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004336{
4337/* level 257 SMB_ */
4338 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
4339 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004340 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004341 int rc = 0;
4342 int bytes_returned = 0;
4343 int name_len;
4344 __u16 params, byte_count;
4345
Joe Perchesb6b38f72010-04-21 03:50:45 +00004346 cFYI(1, "In FindFirst for %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004347
4348findFirstRetry:
4349 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4350 (void **) &pSMBr);
4351 if (rc)
4352 return rc;
4353
4354 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4355 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004356 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4357 PATH_MAX, nls_codepage, remap);
Steve French737b7582005-04-28 22:41:06 -07004358 /* We can not add the asterik earlier in case
4359 it got remapped to 0xF03A as if it were part of the
4360 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004361 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07004362 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07004363 pSMB->FileName[name_len+1] = 0;
4364 pSMB->FileName[name_len+2] = '*';
4365 pSMB->FileName[name_len+3] = 0;
4366 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004367 pSMB->FileName[name_len] = 0; /* null terminate just in case */
4368 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07004369 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004370 } else { /* BB add check for overrun of SMB buf BB */
4371 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004372/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00004373 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004374 free buffer exit; BB */
4375 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07004376 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07004377 pSMB->FileName[name_len+1] = '*';
4378 pSMB->FileName[name_len+2] = 0;
4379 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004380 }
4381
4382 params = 12 + name_len /* includes null */ ;
4383 pSMB->TotalDataCount = 0; /* no EAs */
4384 pSMB->MaxParameterCount = cpu_to_le16(10);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004385 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004386 pSMB->MaxSetupCount = 0;
4387 pSMB->Reserved = 0;
4388 pSMB->Flags = 0;
4389 pSMB->Timeout = 0;
4390 pSMB->Reserved2 = 0;
4391 byte_count = params + 1 /* pad */ ;
4392 pSMB->TotalParameterCount = cpu_to_le16(params);
4393 pSMB->ParameterCount = pSMB->TotalParameterCount;
4394 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00004395 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
4396 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004397 pSMB->DataCount = 0;
4398 pSMB->DataOffset = 0;
4399 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
4400 pSMB->Reserved3 = 0;
4401 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
4402 pSMB->SearchAttributes =
4403 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
4404 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00004405 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
4406 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
Linus Torvalds1da177e2005-04-16 15:20:36 -07004407 CIFS_SEARCH_RETURN_RESUME);
4408 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4409
4410 /* BB what should we set StorageType to? Does it matter? BB */
4411 pSMB->SearchStorageType = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004412 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004413 pSMB->ByteCount = cpu_to_le16(byte_count);
4414
4415 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4416 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07004417 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004418
Steve French88274812006-03-09 22:21:45 +00004419 if (rc) {/* BB add logic to retry regular search if Unix search
4420 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004421 /* BB Add code to handle unsupported level rc */
Joe Perchesb6b38f72010-04-21 03:50:45 +00004422 cFYI(1, "Error in FindFirst = %d", rc);
Steve French1982c342005-08-17 12:38:22 -07004423
Steve French88274812006-03-09 22:21:45 +00004424 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004425
4426 /* BB eventually could optimize out free and realloc of buf */
4427 /* for this case */
4428 if (rc == -EAGAIN)
4429 goto findFirstRetry;
4430 } else { /* decode response */
4431 /* BB remember to free buffer if error BB */
4432 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00004433 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004434 unsigned int lnoff;
4435
Linus Torvalds1da177e2005-04-16 15:20:36 -07004436 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004437 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004438 else
Steve French4b18f2a2008-04-29 00:06:05 +00004439 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004440
4441 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004442 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00004443 psrch_inf->srch_entries_start =
4444 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004445 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004446 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
4447 le16_to_cpu(pSMBr->t2.ParameterOffset));
4448
Steve French790fe572007-07-07 19:25:05 +00004449 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004450 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004451 else
Steve French4b18f2a2008-04-29 00:06:05 +00004452 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004453
Steve French50c2f752007-07-13 00:33:32 +00004454 psrch_inf->entries_in_buffer =
4455 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00004456 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004457 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004458 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004459 if (CIFSMaxBufSize < lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004460 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00004461 psrch_inf->last_entry = NULL;
4462 return rc;
4463 }
4464
Steve French0752f152008-10-07 20:03:33 +00004465 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00004466 lnoff;
4467
Linus Torvalds1da177e2005-04-16 15:20:36 -07004468 *pnetfid = parms->SearchHandle;
4469 } else {
4470 cifs_buf_release(pSMB);
4471 }
4472 }
4473
4474 return rc;
4475}
4476
Steve French96daf2b2011-05-27 04:34:02 +00004477int CIFSFindNext(const int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004478 __u16 searchHandle, struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004479{
4480 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
4481 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004482 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004483 char *response_data;
4484 int rc = 0;
Jeff Layton9438fab2011-08-23 07:21:28 -04004485 int bytes_returned;
4486 unsigned int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004487 __u16 params, byte_count;
4488
Joe Perchesb6b38f72010-04-21 03:50:45 +00004489 cFYI(1, "In FindNext");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004490
Steve French4b18f2a2008-04-29 00:06:05 +00004491 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004492 return -ENOENT;
4493
4494 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4495 (void **) &pSMBr);
4496 if (rc)
4497 return rc;
4498
Steve French50c2f752007-07-13 00:33:32 +00004499 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004500 byte_count = 0;
4501 pSMB->TotalDataCount = 0; /* no EAs */
4502 pSMB->MaxParameterCount = cpu_to_le16(8);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004503 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004504 pSMB->MaxSetupCount = 0;
4505 pSMB->Reserved = 0;
4506 pSMB->Flags = 0;
4507 pSMB->Timeout = 0;
4508 pSMB->Reserved2 = 0;
4509 pSMB->ParameterOffset = cpu_to_le16(
4510 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
4511 pSMB->DataCount = 0;
4512 pSMB->DataOffset = 0;
4513 pSMB->SetupCount = 1;
4514 pSMB->Reserved3 = 0;
4515 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
4516 pSMB->SearchHandle = searchHandle; /* always kept as le */
4517 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00004518 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004519 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4520 pSMB->ResumeKey = psrch_inf->resume_key;
4521 pSMB->SearchFlags =
4522 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
4523
4524 name_len = psrch_inf->resume_name_len;
4525 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00004526 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004527 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
4528 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07004529 /* 14 byte parm len above enough for 2 byte null terminator */
4530 pSMB->ResumeFileName[name_len] = 0;
4531 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004532 } else {
4533 rc = -EINVAL;
4534 goto FNext2_err_exit;
4535 }
4536 byte_count = params + 1 /* pad */ ;
4537 pSMB->TotalParameterCount = cpu_to_le16(params);
4538 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004539 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004540 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004541
Linus Torvalds1da177e2005-04-16 15:20:36 -07004542 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4543 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07004544 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004545 if (rc) {
4546 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00004547 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07004548 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00004549 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004550 } else
Joe Perchesb6b38f72010-04-21 03:50:45 +00004551 cFYI(1, "FindNext returned = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004552 } else { /* decode response */
4553 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00004554
Steve French790fe572007-07-07 19:25:05 +00004555 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004556 unsigned int lnoff;
4557
Linus Torvalds1da177e2005-04-16 15:20:36 -07004558 /* BB fixme add lock for file (srch_info) struct here */
4559 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004560 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004561 else
Steve French4b18f2a2008-04-29 00:06:05 +00004562 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004563 response_data = (char *) &pSMBr->hdr.Protocol +
4564 le16_to_cpu(pSMBr->t2.ParameterOffset);
4565 parms = (T2_FNEXT_RSP_PARMS *)response_data;
4566 response_data = (char *)&pSMBr->hdr.Protocol +
4567 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00004568 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00004569 cifs_small_buf_release(
4570 psrch_inf->ntwrk_buf_start);
4571 else
4572 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004573 psrch_inf->srch_entries_start = response_data;
4574 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004575 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00004576 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004577 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004578 else
Steve French4b18f2a2008-04-29 00:06:05 +00004579 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00004580 psrch_inf->entries_in_buffer =
4581 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004582 psrch_inf->index_of_last_entry +=
4583 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004584 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004585 if (CIFSMaxBufSize < lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004586 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00004587 psrch_inf->last_entry = NULL;
4588 return rc;
4589 } else
4590 psrch_inf->last_entry =
4591 psrch_inf->srch_entries_start + lnoff;
4592
Joe Perchesb6b38f72010-04-21 03:50:45 +00004593/* cFYI(1, "fnxt2 entries in buf %d index_of_last %d",
4594 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004595
4596 /* BB fixme add unlock here */
4597 }
4598
4599 }
4600
4601 /* BB On error, should we leave previous search buf (and count and
4602 last entry fields) intact or free the previous one? */
4603
4604 /* Note: On -EAGAIN error only caller can retry on handle based calls
4605 since file handle passed in no longer valid */
4606FNext2_err_exit:
4607 if (rc != 0)
4608 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004609 return rc;
4610}
4611
4612int
Steve French96daf2b2011-05-27 04:34:02 +00004613CIFSFindClose(const int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004614 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004615{
4616 int rc = 0;
4617 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004618
Joe Perchesb6b38f72010-04-21 03:50:45 +00004619 cFYI(1, "In CIFSSMBFindClose");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004620 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
4621
4622 /* no sense returning error if session restarted
4623 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00004624 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004625 return 0;
4626 if (rc)
4627 return rc;
4628
Linus Torvalds1da177e2005-04-16 15:20:36 -07004629 pSMB->FileID = searchHandle;
4630 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00004631 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004632 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00004633 cERROR(1, "Send error in FindClose = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00004634
Steve Frencha4544342005-08-24 13:59:35 -07004635 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004636
4637 /* Since session is dead, search handle closed on server already */
4638 if (rc == -EAGAIN)
4639 rc = 0;
4640
4641 return rc;
4642}
4643
Linus Torvalds1da177e2005-04-16 15:20:36 -07004644int
Steve French96daf2b2011-05-27 04:34:02 +00004645CIFSGetSrvInodeNumber(const int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004646 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00004647 __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00004648 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004649{
4650 int rc = 0;
4651 TRANSACTION2_QPI_REQ *pSMB = NULL;
4652 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4653 int name_len, bytes_returned;
4654 __u16 params, byte_count;
4655
Joe Perchesb6b38f72010-04-21 03:50:45 +00004656 cFYI(1, "In GetSrvInodeNum for %s", searchName);
Steve French790fe572007-07-07 19:25:05 +00004657 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00004658 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004659
4660GetInodeNumberRetry:
4661 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004662 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004663 if (rc)
4664 return rc;
4665
Linus Torvalds1da177e2005-04-16 15:20:36 -07004666 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4667 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004668 cifsConvertToUTF16((__le16 *) pSMB->FileName,
4669 searchName, PATH_MAX, nls_codepage,
4670 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004671 name_len++; /* trailing null */
4672 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004673 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004674 name_len = strnlen(searchName, PATH_MAX);
4675 name_len++; /* trailing null */
4676 strncpy(pSMB->FileName, searchName, name_len);
4677 }
4678
4679 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4680 pSMB->TotalDataCount = 0;
4681 pSMB->MaxParameterCount = cpu_to_le16(2);
4682 /* BB find exact max data count below from sess structure BB */
4683 pSMB->MaxDataCount = cpu_to_le16(4000);
4684 pSMB->MaxSetupCount = 0;
4685 pSMB->Reserved = 0;
4686 pSMB->Flags = 0;
4687 pSMB->Timeout = 0;
4688 pSMB->Reserved2 = 0;
4689 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004690 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004691 pSMB->DataCount = 0;
4692 pSMB->DataOffset = 0;
4693 pSMB->SetupCount = 1;
4694 pSMB->Reserved3 = 0;
4695 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4696 byte_count = params + 1 /* pad */ ;
4697 pSMB->TotalParameterCount = cpu_to_le16(params);
4698 pSMB->ParameterCount = pSMB->TotalParameterCount;
4699 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4700 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004701 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004702 pSMB->ByteCount = cpu_to_le16(byte_count);
4703
4704 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4705 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4706 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004707 cFYI(1, "error %d in QueryInternalInfo", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004708 } else {
4709 /* decode response */
4710 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004711 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04004712 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004713 /* If rc should we check for EOPNOSUPP and
4714 disable the srvino flag? or in caller? */
4715 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00004716 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004717 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4718 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00004719 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004720 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00004721 if (count < 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004722 cFYI(1, "Illegal size ret in QryIntrnlInf");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004723 rc = -EIO;
4724 goto GetInodeNumOut;
4725 }
4726 pfinfo = (struct file_internal_info *)
4727 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00004728 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004729 }
4730 }
4731GetInodeNumOut:
4732 cifs_buf_release(pSMB);
4733 if (rc == -EAGAIN)
4734 goto GetInodeNumberRetry;
4735 return rc;
4736}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004737
Igor Mammedovfec45852008-05-16 13:06:30 +04004738/* parses DFS refferal V3 structure
4739 * caller is responsible for freeing target_nodes
4740 * returns:
4741 * on success - 0
4742 * on failure - errno
4743 */
4744static int
Steve Frencha1fe78f2008-05-16 18:48:38 +00004745parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
Igor Mammedovfec45852008-05-16 13:06:30 +04004746 unsigned int *num_of_nodes,
4747 struct dfs_info3_param **target_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004748 const struct nls_table *nls_codepage, int remap,
4749 const char *searchName)
Igor Mammedovfec45852008-05-16 13:06:30 +04004750{
4751 int i, rc = 0;
4752 char *data_end;
4753 bool is_unicode;
4754 struct dfs_referral_level_3 *ref;
4755
Harvey Harrison5ca33c62008-07-23 17:45:58 -07004756 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4757 is_unicode = true;
4758 else
4759 is_unicode = false;
Igor Mammedovfec45852008-05-16 13:06:30 +04004760 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
4761
4762 if (*num_of_nodes < 1) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004763 cERROR(1, "num_referrals: must be at least > 0,"
4764 "but we get num_referrals = %d\n", *num_of_nodes);
Igor Mammedovfec45852008-05-16 13:06:30 +04004765 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004766 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004767 }
4768
4769 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
Al Viro1d92cfd2008-06-02 10:59:02 +01004770 if (ref->VersionNumber != cpu_to_le16(3)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004771 cERROR(1, "Referrals of V%d version are not supported,"
4772 "should be V3", le16_to_cpu(ref->VersionNumber));
Igor Mammedovfec45852008-05-16 13:06:30 +04004773 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004774 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004775 }
4776
4777 /* get the upper boundary of the resp buffer */
4778 data_end = (char *)(&(pSMBr->PathConsumed)) +
4779 le16_to_cpu(pSMBr->t2.DataCount);
4780
Steve Frenchf19159d2010-04-21 04:12:10 +00004781 cFYI(1, "num_referrals: %d dfs flags: 0x%x ...\n",
Igor Mammedovfec45852008-05-16 13:06:30 +04004782 *num_of_nodes,
Joe Perchesb6b38f72010-04-21 03:50:45 +00004783 le32_to_cpu(pSMBr->DFSFlags));
Igor Mammedovfec45852008-05-16 13:06:30 +04004784
4785 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
4786 *num_of_nodes, GFP_KERNEL);
4787 if (*target_nodes == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004788 cERROR(1, "Failed to allocate buffer for target_nodes\n");
Igor Mammedovfec45852008-05-16 13:06:30 +04004789 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004790 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004791 }
4792
Daniel Mack3ad2f3fb2010-02-03 08:01:28 +08004793 /* collect necessary data from referrals */
Igor Mammedovfec45852008-05-16 13:06:30 +04004794 for (i = 0; i < *num_of_nodes; i++) {
4795 char *temp;
4796 int max_len;
4797 struct dfs_info3_param *node = (*target_nodes)+i;
4798
Steve French0e0d2cf2009-05-01 05:27:32 +00004799 node->flags = le32_to_cpu(pSMBr->DFSFlags);
Igor Mammedov2c556082008-10-23 13:58:42 +04004800 if (is_unicode) {
Jeff Layton331c3132008-12-17 06:31:53 -05004801 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4802 GFP_KERNEL);
Steve French2920ee22009-08-31 15:27:26 +00004803 if (tmp == NULL) {
4804 rc = -ENOMEM;
4805 goto parse_DFS_referrals_exit;
4806 }
Steve Frenchacbbb762012-01-18 22:32:33 -06004807 cifsConvertToUTF16((__le16 *) tmp, searchName,
4808 PATH_MAX, nls_codepage, remap);
4809 node->path_consumed = cifs_utf16_bytes(tmp,
Jeff Layton69f801f2009-04-30 06:46:32 -04004810 le16_to_cpu(pSMBr->PathConsumed),
Igor Mammedov2c556082008-10-23 13:58:42 +04004811 nls_codepage);
4812 kfree(tmp);
4813 } else
4814 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4815
Igor Mammedovfec45852008-05-16 13:06:30 +04004816 node->server_type = le16_to_cpu(ref->ServerType);
4817 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4818
4819 /* copy DfsPath */
4820 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4821 max_len = data_end - temp;
Steve Frenchacbbb762012-01-18 22:32:33 -06004822 node->path_name = cifs_strndup_from_utf16(temp, max_len,
4823 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004824 if (!node->path_name) {
4825 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004826 goto parse_DFS_referrals_exit;
Jeff Layton066ce682009-04-30 07:16:14 -04004827 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004828
4829 /* copy link target UNC */
4830 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4831 max_len = data_end - temp;
Steve Frenchacbbb762012-01-18 22:32:33 -06004832 node->node_name = cifs_strndup_from_utf16(temp, max_len,
4833 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004834 if (!node->node_name)
4835 rc = -ENOMEM;
Igor Mammedovfec45852008-05-16 13:06:30 +04004836 }
4837
Steve Frencha1fe78f2008-05-16 18:48:38 +00004838parse_DFS_referrals_exit:
Igor Mammedovfec45852008-05-16 13:06:30 +04004839 if (rc) {
4840 free_dfs_info_array(*target_nodes, *num_of_nodes);
4841 *target_nodes = NULL;
4842 *num_of_nodes = 0;
4843 }
4844 return rc;
4845}
4846
Linus Torvalds1da177e2005-04-16 15:20:36 -07004847int
Steve French96daf2b2011-05-27 04:34:02 +00004848CIFSGetDFSRefer(const int xid, struct cifs_ses *ses,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004849 const unsigned char *searchName,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004850 struct dfs_info3_param **target_nodes,
4851 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004852 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004853{
4854/* TRANS2_GET_DFS_REFERRAL */
4855 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4856 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004857 int rc = 0;
4858 int bytes_returned;
4859 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004860 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004861 *num_of_nodes = 0;
4862 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004863
Joe Perchesb6b38f72010-04-21 03:50:45 +00004864 cFYI(1, "In GetDFSRefer the path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004865 if (ses == NULL)
4866 return -ENODEV;
4867getDFSRetry:
4868 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4869 (void **) &pSMBr);
4870 if (rc)
4871 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004872
4873 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004874 but should never be null here anyway */
4875 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004876 pSMB->hdr.Tid = ses->ipc_tid;
4877 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004878 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004879 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004880 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004881 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004882
4883 if (ses->capabilities & CAP_UNICODE) {
4884 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4885 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004886 cifsConvertToUTF16((__le16 *) pSMB->RequestFileName,
4887 searchName, PATH_MAX, nls_codepage,
4888 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004889 name_len++; /* trailing null */
4890 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004891 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004892 name_len = strnlen(searchName, PATH_MAX);
4893 name_len++; /* trailing null */
4894 strncpy(pSMB->RequestFileName, searchName, name_len);
4895 }
4896
Steve French790fe572007-07-07 19:25:05 +00004897 if (ses->server) {
Steve French96daf2b2011-05-27 04:34:02 +00004898 if (ses->server->sec_mode &
Steve French1a4e15a2006-10-12 21:33:51 +00004899 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4900 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4901 }
4902
Steve French50c2f752007-07-13 00:33:32 +00004903 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004904
Linus Torvalds1da177e2005-04-16 15:20:36 -07004905 params = 2 /* level */ + name_len /*includes null */ ;
4906 pSMB->TotalDataCount = 0;
4907 pSMB->DataCount = 0;
4908 pSMB->DataOffset = 0;
4909 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004910 /* BB find exact max SMB PDU from sess structure BB */
4911 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004912 pSMB->MaxSetupCount = 0;
4913 pSMB->Reserved = 0;
4914 pSMB->Flags = 0;
4915 pSMB->Timeout = 0;
4916 pSMB->Reserved2 = 0;
4917 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004918 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004919 pSMB->SetupCount = 1;
4920 pSMB->Reserved3 = 0;
4921 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4922 byte_count = params + 3 /* pad */ ;
4923 pSMB->ParameterCount = cpu_to_le16(params);
4924 pSMB->TotalParameterCount = pSMB->ParameterCount;
4925 pSMB->MaxReferralLevel = cpu_to_le16(3);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004926 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004927 pSMB->ByteCount = cpu_to_le16(byte_count);
4928
4929 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4930 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4931 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004932 cFYI(1, "Send error in GetDFSRefer = %d", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004933 goto GetDFSRefExit;
4934 }
4935 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004936
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004937 /* BB Also check if enough total bytes returned? */
Jeff Layton820a8032011-05-04 08:05:26 -04004938 if (rc || get_bcc(&pSMBr->hdr) < 17) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004939 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004940 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004941 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004942
Joe Perchesb6b38f72010-04-21 03:50:45 +00004943 cFYI(1, "Decoding GetDFSRefer response BCC: %d Offset %d",
Jeff Layton820a8032011-05-04 08:05:26 -04004944 get_bcc(&pSMBr->hdr),
Joe Perchesb6b38f72010-04-21 03:50:45 +00004945 le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04004946
4947 /* parse returned result into more usable form */
Steve Frencha1fe78f2008-05-16 18:48:38 +00004948 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004949 target_nodes, nls_codepage, remap,
4950 searchName);
Igor Mammedovfec45852008-05-16 13:06:30 +04004951
Linus Torvalds1da177e2005-04-16 15:20:36 -07004952GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004953 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004954
4955 if (rc == -EAGAIN)
4956 goto getDFSRetry;
4957
4958 return rc;
4959}
4960
Steve French20962432005-09-21 22:05:57 -07004961/* Query File System Info such as free space to old servers such as Win 9x */
4962int
Steve French96daf2b2011-05-27 04:34:02 +00004963SMBOldQFSInfo(const int xid, struct cifs_tcon *tcon, struct kstatfs *FSData)
Steve French20962432005-09-21 22:05:57 -07004964{
4965/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4966 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4967 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4968 FILE_SYSTEM_ALLOC_INFO *response_data;
4969 int rc = 0;
4970 int bytes_returned = 0;
4971 __u16 params, byte_count;
4972
Joe Perchesb6b38f72010-04-21 03:50:45 +00004973 cFYI(1, "OldQFSInfo");
Steve French20962432005-09-21 22:05:57 -07004974oldQFSInfoRetry:
4975 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4976 (void **) &pSMBr);
4977 if (rc)
4978 return rc;
Steve French20962432005-09-21 22:05:57 -07004979
4980 params = 2; /* level */
4981 pSMB->TotalDataCount = 0;
4982 pSMB->MaxParameterCount = cpu_to_le16(2);
4983 pSMB->MaxDataCount = cpu_to_le16(1000);
4984 pSMB->MaxSetupCount = 0;
4985 pSMB->Reserved = 0;
4986 pSMB->Flags = 0;
4987 pSMB->Timeout = 0;
4988 pSMB->Reserved2 = 0;
4989 byte_count = params + 1 /* pad */ ;
4990 pSMB->TotalParameterCount = cpu_to_le16(params);
4991 pSMB->ParameterCount = pSMB->TotalParameterCount;
4992 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4993 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4994 pSMB->DataCount = 0;
4995 pSMB->DataOffset = 0;
4996 pSMB->SetupCount = 1;
4997 pSMB->Reserved3 = 0;
4998 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4999 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005000 inc_rfc1001_len(pSMB, byte_count);
Steve French20962432005-09-21 22:05:57 -07005001 pSMB->ByteCount = cpu_to_le16(byte_count);
5002
5003 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5004 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5005 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005006 cFYI(1, "Send error in QFSInfo = %d", rc);
Steve French20962432005-09-21 22:05:57 -07005007 } else { /* decode response */
5008 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5009
Jeff Layton820a8032011-05-04 08:05:26 -04005010 if (rc || get_bcc(&pSMBr->hdr) < 18)
Steve French20962432005-09-21 22:05:57 -07005011 rc = -EIO; /* bad smb */
5012 else {
5013 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesb6b38f72010-04-21 03:50:45 +00005014 cFYI(1, "qfsinf resp BCC: %d Offset %d",
Jeff Layton820a8032011-05-04 08:05:26 -04005015 get_bcc(&pSMBr->hdr), data_offset);
Steve French20962432005-09-21 22:05:57 -07005016
Steve French50c2f752007-07-13 00:33:32 +00005017 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07005018 (((char *) &pSMBr->hdr.Protocol) + data_offset);
5019 FSData->f_bsize =
5020 le16_to_cpu(response_data->BytesPerSector) *
5021 le32_to_cpu(response_data->
5022 SectorsPerAllocationUnit);
5023 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00005024 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07005025 FSData->f_bfree = FSData->f_bavail =
5026 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesb6b38f72010-04-21 03:50:45 +00005027 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
5028 (unsigned long long)FSData->f_blocks,
5029 (unsigned long long)FSData->f_bfree,
5030 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07005031 }
5032 }
5033 cifs_buf_release(pSMB);
5034
5035 if (rc == -EAGAIN)
5036 goto oldQFSInfoRetry;
5037
5038 return rc;
5039}
5040
Linus Torvalds1da177e2005-04-16 15:20:36 -07005041int
Steve French96daf2b2011-05-27 04:34:02 +00005042CIFSSMBQFSInfo(const int xid, struct cifs_tcon *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005043{
5044/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
5045 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5046 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5047 FILE_SYSTEM_INFO *response_data;
5048 int rc = 0;
5049 int bytes_returned = 0;
5050 __u16 params, byte_count;
5051
Joe Perchesb6b38f72010-04-21 03:50:45 +00005052 cFYI(1, "In QFSInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005053QFSInfoRetry:
5054 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5055 (void **) &pSMBr);
5056 if (rc)
5057 return rc;
5058
5059 params = 2; /* level */
5060 pSMB->TotalDataCount = 0;
5061 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07005062 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005063 pSMB->MaxSetupCount = 0;
5064 pSMB->Reserved = 0;
5065 pSMB->Flags = 0;
5066 pSMB->Timeout = 0;
5067 pSMB->Reserved2 = 0;
5068 byte_count = params + 1 /* pad */ ;
5069 pSMB->TotalParameterCount = cpu_to_le16(params);
5070 pSMB->ParameterCount = pSMB->TotalParameterCount;
5071 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005072 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005073 pSMB->DataCount = 0;
5074 pSMB->DataOffset = 0;
5075 pSMB->SetupCount = 1;
5076 pSMB->Reserved3 = 0;
5077 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5078 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005079 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005080 pSMB->ByteCount = cpu_to_le16(byte_count);
5081
5082 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5083 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5084 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005085 cFYI(1, "Send error in QFSInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005086 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00005087 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005088
Jeff Layton820a8032011-05-04 08:05:26 -04005089 if (rc || get_bcc(&pSMBr->hdr) < 24)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005090 rc = -EIO; /* bad smb */
5091 else {
5092 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005093
5094 response_data =
5095 (FILE_SYSTEM_INFO
5096 *) (((char *) &pSMBr->hdr.Protocol) +
5097 data_offset);
5098 FSData->f_bsize =
5099 le32_to_cpu(response_data->BytesPerSector) *
5100 le32_to_cpu(response_data->
5101 SectorsPerAllocationUnit);
5102 FSData->f_blocks =
5103 le64_to_cpu(response_data->TotalAllocationUnits);
5104 FSData->f_bfree = FSData->f_bavail =
5105 le64_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesb6b38f72010-04-21 03:50:45 +00005106 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
5107 (unsigned long long)FSData->f_blocks,
5108 (unsigned long long)FSData->f_bfree,
5109 FSData->f_bsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005110 }
5111 }
5112 cifs_buf_release(pSMB);
5113
5114 if (rc == -EAGAIN)
5115 goto QFSInfoRetry;
5116
5117 return rc;
5118}
5119
5120int
Steve French96daf2b2011-05-27 04:34:02 +00005121CIFSSMBQFSAttributeInfo(const int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005122{
5123/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
5124 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5125 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5126 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
5127 int rc = 0;
5128 int bytes_returned = 0;
5129 __u16 params, byte_count;
5130
Joe Perchesb6b38f72010-04-21 03:50:45 +00005131 cFYI(1, "In QFSAttributeInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005132QFSAttributeRetry:
5133 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5134 (void **) &pSMBr);
5135 if (rc)
5136 return rc;
5137
5138 params = 2; /* level */
5139 pSMB->TotalDataCount = 0;
5140 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005141 /* BB find exact max SMB PDU from sess structure BB */
5142 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005143 pSMB->MaxSetupCount = 0;
5144 pSMB->Reserved = 0;
5145 pSMB->Flags = 0;
5146 pSMB->Timeout = 0;
5147 pSMB->Reserved2 = 0;
5148 byte_count = params + 1 /* pad */ ;
5149 pSMB->TotalParameterCount = cpu_to_le16(params);
5150 pSMB->ParameterCount = pSMB->TotalParameterCount;
5151 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005152 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005153 pSMB->DataCount = 0;
5154 pSMB->DataOffset = 0;
5155 pSMB->SetupCount = 1;
5156 pSMB->Reserved3 = 0;
5157 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5158 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005159 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005160 pSMB->ByteCount = cpu_to_le16(byte_count);
5161
5162 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5163 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5164 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005165 cERROR(1, "Send error in QFSAttributeInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005166 } else { /* decode response */
5167 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5168
Jeff Layton820a8032011-05-04 08:05:26 -04005169 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Steve French50c2f752007-07-13 00:33:32 +00005170 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005171 rc = -EIO; /* bad smb */
5172 } else {
5173 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5174 response_data =
5175 (FILE_SYSTEM_ATTRIBUTE_INFO
5176 *) (((char *) &pSMBr->hdr.Protocol) +
5177 data_offset);
5178 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005179 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005180 }
5181 }
5182 cifs_buf_release(pSMB);
5183
5184 if (rc == -EAGAIN)
5185 goto QFSAttributeRetry;
5186
5187 return rc;
5188}
5189
5190int
Steve French96daf2b2011-05-27 04:34:02 +00005191CIFSSMBQFSDeviceInfo(const int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005192{
5193/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
5194 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5195 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5196 FILE_SYSTEM_DEVICE_INFO *response_data;
5197 int rc = 0;
5198 int bytes_returned = 0;
5199 __u16 params, byte_count;
5200
Joe Perchesb6b38f72010-04-21 03:50:45 +00005201 cFYI(1, "In QFSDeviceInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005202QFSDeviceRetry:
5203 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5204 (void **) &pSMBr);
5205 if (rc)
5206 return rc;
5207
5208 params = 2; /* level */
5209 pSMB->TotalDataCount = 0;
5210 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005211 /* BB find exact max SMB PDU from sess structure BB */
5212 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005213 pSMB->MaxSetupCount = 0;
5214 pSMB->Reserved = 0;
5215 pSMB->Flags = 0;
5216 pSMB->Timeout = 0;
5217 pSMB->Reserved2 = 0;
5218 byte_count = params + 1 /* pad */ ;
5219 pSMB->TotalParameterCount = cpu_to_le16(params);
5220 pSMB->ParameterCount = pSMB->TotalParameterCount;
5221 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005222 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005223
5224 pSMB->DataCount = 0;
5225 pSMB->DataOffset = 0;
5226 pSMB->SetupCount = 1;
5227 pSMB->Reserved3 = 0;
5228 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5229 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005230 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005231 pSMB->ByteCount = cpu_to_le16(byte_count);
5232
5233 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5234 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5235 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005236 cFYI(1, "Send error in QFSDeviceInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005237 } else { /* decode response */
5238 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5239
Jeff Layton820a8032011-05-04 08:05:26 -04005240 if (rc || get_bcc(&pSMBr->hdr) <
5241 sizeof(FILE_SYSTEM_DEVICE_INFO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005242 rc = -EIO; /* bad smb */
5243 else {
5244 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5245 response_data =
Steve French737b7582005-04-28 22:41:06 -07005246 (FILE_SYSTEM_DEVICE_INFO *)
5247 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07005248 data_offset);
5249 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005250 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005251 }
5252 }
5253 cifs_buf_release(pSMB);
5254
5255 if (rc == -EAGAIN)
5256 goto QFSDeviceRetry;
5257
5258 return rc;
5259}
5260
5261int
Steve French96daf2b2011-05-27 04:34:02 +00005262CIFSSMBQFSUnixInfo(const int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005263{
5264/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
5265 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5266 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5267 FILE_SYSTEM_UNIX_INFO *response_data;
5268 int rc = 0;
5269 int bytes_returned = 0;
5270 __u16 params, byte_count;
5271
Joe Perchesb6b38f72010-04-21 03:50:45 +00005272 cFYI(1, "In QFSUnixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005273QFSUnixRetry:
Jeff Laytonf5695992010-09-29 15:27:08 -04005274 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5275 (void **) &pSMB, (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005276 if (rc)
5277 return rc;
5278
5279 params = 2; /* level */
5280 pSMB->TotalDataCount = 0;
5281 pSMB->DataCount = 0;
5282 pSMB->DataOffset = 0;
5283 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005284 /* BB find exact max SMB PDU from sess structure BB */
5285 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005286 pSMB->MaxSetupCount = 0;
5287 pSMB->Reserved = 0;
5288 pSMB->Flags = 0;
5289 pSMB->Timeout = 0;
5290 pSMB->Reserved2 = 0;
5291 byte_count = params + 1 /* pad */ ;
5292 pSMB->ParameterCount = cpu_to_le16(params);
5293 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005294 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5295 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005296 pSMB->SetupCount = 1;
5297 pSMB->Reserved3 = 0;
5298 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5299 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005300 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005301 pSMB->ByteCount = cpu_to_le16(byte_count);
5302
5303 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5304 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5305 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005306 cERROR(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005307 } else { /* decode response */
5308 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5309
Jeff Layton820a8032011-05-04 08:05:26 -04005310 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005311 rc = -EIO; /* bad smb */
5312 } else {
5313 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5314 response_data =
5315 (FILE_SYSTEM_UNIX_INFO
5316 *) (((char *) &pSMBr->hdr.Protocol) +
5317 data_offset);
5318 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005319 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005320 }
5321 }
5322 cifs_buf_release(pSMB);
5323
5324 if (rc == -EAGAIN)
5325 goto QFSUnixRetry;
5326
5327
5328 return rc;
5329}
5330
Jeremy Allisonac670552005-06-22 17:26:35 -07005331int
Steve French96daf2b2011-05-27 04:34:02 +00005332CIFSSMBSetFSUnixInfo(const int xid, struct cifs_tcon *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07005333{
5334/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
5335 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
5336 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
5337 int rc = 0;
5338 int bytes_returned = 0;
5339 __u16 params, param_offset, offset, byte_count;
5340
Joe Perchesb6b38f72010-04-21 03:50:45 +00005341 cFYI(1, "In SETFSUnixInfo");
Jeremy Allisonac670552005-06-22 17:26:35 -07005342SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00005343 /* BB switch to small buf init to save memory */
Jeff Laytonf5695992010-09-29 15:27:08 -04005344 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5345 (void **) &pSMB, (void **) &pSMBr);
Jeremy Allisonac670552005-06-22 17:26:35 -07005346 if (rc)
5347 return rc;
5348
5349 params = 4; /* 2 bytes zero followed by info level. */
5350 pSMB->MaxSetupCount = 0;
5351 pSMB->Reserved = 0;
5352 pSMB->Flags = 0;
5353 pSMB->Timeout = 0;
5354 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00005355 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
5356 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07005357 offset = param_offset + params;
5358
5359 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00005360 /* BB find exact max SMB PDU from sess structure BB */
5361 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07005362 pSMB->SetupCount = 1;
5363 pSMB->Reserved3 = 0;
5364 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
5365 byte_count = 1 /* pad */ + params + 12;
5366
5367 pSMB->DataCount = cpu_to_le16(12);
5368 pSMB->ParameterCount = cpu_to_le16(params);
5369 pSMB->TotalDataCount = pSMB->DataCount;
5370 pSMB->TotalParameterCount = pSMB->ParameterCount;
5371 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5372 pSMB->DataOffset = cpu_to_le16(offset);
5373
5374 /* Params. */
5375 pSMB->FileNum = 0;
5376 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
5377
5378 /* Data. */
5379 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
5380 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
5381 pSMB->ClientUnixCap = cpu_to_le64(cap);
5382
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005383 inc_rfc1001_len(pSMB, byte_count);
Jeremy Allisonac670552005-06-22 17:26:35 -07005384 pSMB->ByteCount = cpu_to_le16(byte_count);
5385
5386 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5387 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5388 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005389 cERROR(1, "Send error in SETFSUnixInfo = %d", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07005390 } else { /* decode response */
5391 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00005392 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07005393 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07005394 }
5395 cifs_buf_release(pSMB);
5396
5397 if (rc == -EAGAIN)
5398 goto SETFSUnixRetry;
5399
5400 return rc;
5401}
5402
5403
Linus Torvalds1da177e2005-04-16 15:20:36 -07005404
5405int
Steve French96daf2b2011-05-27 04:34:02 +00005406CIFSSMBQFSPosixInfo(const int xid, struct cifs_tcon *tcon,
Steve French737b7582005-04-28 22:41:06 -07005407 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005408{
5409/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
5410 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5411 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5412 FILE_SYSTEM_POSIX_INFO *response_data;
5413 int rc = 0;
5414 int bytes_returned = 0;
5415 __u16 params, byte_count;
5416
Joe Perchesb6b38f72010-04-21 03:50:45 +00005417 cFYI(1, "In QFSPosixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005418QFSPosixRetry:
5419 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5420 (void **) &pSMBr);
5421 if (rc)
5422 return rc;
5423
5424 params = 2; /* level */
5425 pSMB->TotalDataCount = 0;
5426 pSMB->DataCount = 0;
5427 pSMB->DataOffset = 0;
5428 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005429 /* BB find exact max SMB PDU from sess structure BB */
5430 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005431 pSMB->MaxSetupCount = 0;
5432 pSMB->Reserved = 0;
5433 pSMB->Flags = 0;
5434 pSMB->Timeout = 0;
5435 pSMB->Reserved2 = 0;
5436 byte_count = params + 1 /* pad */ ;
5437 pSMB->ParameterCount = cpu_to_le16(params);
5438 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005439 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5440 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005441 pSMB->SetupCount = 1;
5442 pSMB->Reserved3 = 0;
5443 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5444 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005445 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005446 pSMB->ByteCount = cpu_to_le16(byte_count);
5447
5448 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5449 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5450 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005451 cFYI(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005452 } else { /* decode response */
5453 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5454
Jeff Layton820a8032011-05-04 08:05:26 -04005455 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005456 rc = -EIO; /* bad smb */
5457 } else {
5458 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5459 response_data =
5460 (FILE_SYSTEM_POSIX_INFO
5461 *) (((char *) &pSMBr->hdr.Protocol) +
5462 data_offset);
5463 FSData->f_bsize =
5464 le32_to_cpu(response_data->BlockSize);
5465 FSData->f_blocks =
5466 le64_to_cpu(response_data->TotalBlocks);
5467 FSData->f_bfree =
5468 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00005469 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005470 FSData->f_bavail = FSData->f_bfree;
5471 } else {
5472 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00005473 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005474 }
Steve French790fe572007-07-07 19:25:05 +00005475 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005476 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00005477 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00005478 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005479 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00005480 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005481 }
5482 }
5483 cifs_buf_release(pSMB);
5484
5485 if (rc == -EAGAIN)
5486 goto QFSPosixRetry;
5487
5488 return rc;
5489}
5490
5491
Steve French50c2f752007-07-13 00:33:32 +00005492/* We can not use write of zero bytes trick to
5493 set file size due to need for large file support. Also note that
5494 this SetPathInfo is preferred to SetFileInfo based method in next
Linus Torvalds1da177e2005-04-16 15:20:36 -07005495 routine which is only needed to work around a sharing violation bug
5496 in Samba which this routine can run into */
5497
5498int
Steve French96daf2b2011-05-27 04:34:02 +00005499CIFSSMBSetEOF(const int xid, struct cifs_tcon *tcon, const char *fileName,
Steve French4b18f2a2008-04-29 00:06:05 +00005500 __u64 size, bool SetAllocation,
Steve French737b7582005-04-28 22:41:06 -07005501 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005502{
5503 struct smb_com_transaction2_spi_req *pSMB = NULL;
5504 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5505 struct file_end_of_file_info *parm_data;
5506 int name_len;
5507 int rc = 0;
5508 int bytes_returned = 0;
5509 __u16 params, byte_count, data_count, param_offset, offset;
5510
Joe Perchesb6b38f72010-04-21 03:50:45 +00005511 cFYI(1, "In SetEOF");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005512SetEOFRetry:
5513 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5514 (void **) &pSMBr);
5515 if (rc)
5516 return rc;
5517
5518 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5519 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005520 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5521 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005522 name_len++; /* trailing null */
5523 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005524 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005525 name_len = strnlen(fileName, PATH_MAX);
5526 name_len++; /* trailing null */
5527 strncpy(pSMB->FileName, fileName, name_len);
5528 }
5529 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005530 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005531 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07005532 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005533 pSMB->MaxSetupCount = 0;
5534 pSMB->Reserved = 0;
5535 pSMB->Flags = 0;
5536 pSMB->Timeout = 0;
5537 pSMB->Reserved2 = 0;
5538 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005539 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005540 offset = param_offset + params;
Steve French790fe572007-07-07 19:25:05 +00005541 if (SetAllocation) {
Steve French50c2f752007-07-13 00:33:32 +00005542 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5543 pSMB->InformationLevel =
5544 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5545 else
5546 pSMB->InformationLevel =
5547 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5548 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005549 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5550 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005551 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005552 else
5553 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005554 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005555 }
5556
5557 parm_data =
5558 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
5559 offset);
5560 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5561 pSMB->DataOffset = cpu_to_le16(offset);
5562 pSMB->SetupCount = 1;
5563 pSMB->Reserved3 = 0;
5564 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5565 byte_count = 3 /* pad */ + params + data_count;
5566 pSMB->DataCount = cpu_to_le16(data_count);
5567 pSMB->TotalDataCount = pSMB->DataCount;
5568 pSMB->ParameterCount = cpu_to_le16(params);
5569 pSMB->TotalParameterCount = pSMB->ParameterCount;
5570 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005571 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005572 parm_data->FileSize = cpu_to_le64(size);
5573 pSMB->ByteCount = cpu_to_le16(byte_count);
5574 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5575 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005576 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005577 cFYI(1, "SetPathInfo (file size) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005578
5579 cifs_buf_release(pSMB);
5580
5581 if (rc == -EAGAIN)
5582 goto SetEOFRetry;
5583
5584 return rc;
5585}
5586
5587int
Steve French96daf2b2011-05-27 04:34:02 +00005588CIFSSMBSetFileSize(const int xid, struct cifs_tcon *tcon, __u64 size,
Steve French4b18f2a2008-04-29 00:06:05 +00005589 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005590{
5591 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005592 struct file_end_of_file_info *parm_data;
5593 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005594 __u16 params, param_offset, offset, byte_count, count;
5595
Joe Perchesb6b38f72010-04-21 03:50:45 +00005596 cFYI(1, "SetFileSize (via SetFileInfo) %lld",
5597 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07005598 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5599
Linus Torvalds1da177e2005-04-16 15:20:36 -07005600 if (rc)
5601 return rc;
5602
5603 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5604 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005605
Linus Torvalds1da177e2005-04-16 15:20:36 -07005606 params = 6;
5607 pSMB->MaxSetupCount = 0;
5608 pSMB->Reserved = 0;
5609 pSMB->Flags = 0;
5610 pSMB->Timeout = 0;
5611 pSMB->Reserved2 = 0;
5612 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5613 offset = param_offset + params;
5614
Linus Torvalds1da177e2005-04-16 15:20:36 -07005615 count = sizeof(struct file_end_of_file_info);
5616 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005617 /* BB find exact max SMB PDU from sess structure BB */
5618 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005619 pSMB->SetupCount = 1;
5620 pSMB->Reserved3 = 0;
5621 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5622 byte_count = 3 /* pad */ + params + count;
5623 pSMB->DataCount = cpu_to_le16(count);
5624 pSMB->ParameterCount = cpu_to_le16(params);
5625 pSMB->TotalDataCount = pSMB->DataCount;
5626 pSMB->TotalParameterCount = pSMB->ParameterCount;
5627 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5628 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00005629 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
5630 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005631 pSMB->DataOffset = cpu_to_le16(offset);
5632 parm_data->FileSize = cpu_to_le64(size);
5633 pSMB->Fid = fid;
Steve French790fe572007-07-07 19:25:05 +00005634 if (SetAllocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005635 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5636 pSMB->InformationLevel =
5637 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5638 else
5639 pSMB->InformationLevel =
5640 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00005641 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005642 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5643 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005644 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005645 else
5646 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005647 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005648 }
5649 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005650 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005651 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French133672e2007-11-13 22:41:37 +00005652 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005653 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005654 cFYI(1, "Send error in SetFileInfo (SetFileSize) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005655 }
5656
Steve French50c2f752007-07-13 00:33:32 +00005657 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005658 since file handle passed in no longer valid */
5659
5660 return rc;
5661}
5662
Steve French50c2f752007-07-13 00:33:32 +00005663/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07005664 an open handle, rather than by pathname - this is awkward due to
5665 potential access conflicts on the open, but it is unavoidable for these
5666 old servers since the only other choice is to go from 100 nanosecond DCE
5667 time and resort to the original setpathinfo level which takes the ancient
5668 DOS time format with 2 second granularity */
5669int
Steve French96daf2b2011-05-27 04:34:02 +00005670CIFSSMBSetFileInfo(const int xid, struct cifs_tcon *tcon,
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005671 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005672{
5673 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005674 char *data_offset;
5675 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005676 __u16 params, param_offset, offset, byte_count, count;
5677
Joe Perchesb6b38f72010-04-21 03:50:45 +00005678 cFYI(1, "Set Times (via SetFileInfo)");
Steve Frenchcd634992005-04-28 22:41:10 -07005679 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5680
Linus Torvalds1da177e2005-04-16 15:20:36 -07005681 if (rc)
5682 return rc;
5683
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005684 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5685 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005686
Linus Torvalds1da177e2005-04-16 15:20:36 -07005687 params = 6;
5688 pSMB->MaxSetupCount = 0;
5689 pSMB->Reserved = 0;
5690 pSMB->Flags = 0;
5691 pSMB->Timeout = 0;
5692 pSMB->Reserved2 = 0;
5693 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5694 offset = param_offset + params;
5695
Steve French50c2f752007-07-13 00:33:32 +00005696 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005697
Steve French26f57362007-08-30 22:09:15 +00005698 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005699 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005700 /* BB find max SMB PDU from sess */
5701 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005702 pSMB->SetupCount = 1;
5703 pSMB->Reserved3 = 0;
5704 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5705 byte_count = 3 /* pad */ + params + count;
5706 pSMB->DataCount = cpu_to_le16(count);
5707 pSMB->ParameterCount = cpu_to_le16(params);
5708 pSMB->TotalDataCount = pSMB->DataCount;
5709 pSMB->TotalParameterCount = pSMB->ParameterCount;
5710 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5711 pSMB->DataOffset = cpu_to_le16(offset);
5712 pSMB->Fid = fid;
5713 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5714 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5715 else
5716 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5717 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005718 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005719 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005720 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Steve French133672e2007-11-13 22:41:37 +00005721 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005722 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005723 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005724
Steve French50c2f752007-07-13 00:33:32 +00005725 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005726 since file handle passed in no longer valid */
5727
5728 return rc;
5729}
5730
Jeff Layton6d22f092008-09-23 11:48:35 -04005731int
Steve French96daf2b2011-05-27 04:34:02 +00005732CIFSSMBSetFileDisposition(const int xid, struct cifs_tcon *tcon,
Jeff Layton6d22f092008-09-23 11:48:35 -04005733 bool delete_file, __u16 fid, __u32 pid_of_opener)
5734{
5735 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5736 char *data_offset;
5737 int rc = 0;
5738 __u16 params, param_offset, offset, byte_count, count;
5739
Joe Perchesb6b38f72010-04-21 03:50:45 +00005740 cFYI(1, "Set File Disposition (via SetFileInfo)");
Jeff Layton6d22f092008-09-23 11:48:35 -04005741 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5742
5743 if (rc)
5744 return rc;
5745
5746 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5747 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5748
5749 params = 6;
5750 pSMB->MaxSetupCount = 0;
5751 pSMB->Reserved = 0;
5752 pSMB->Flags = 0;
5753 pSMB->Timeout = 0;
5754 pSMB->Reserved2 = 0;
5755 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5756 offset = param_offset + params;
5757
5758 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5759
5760 count = 1;
5761 pSMB->MaxParameterCount = cpu_to_le16(2);
5762 /* BB find max SMB PDU from sess */
5763 pSMB->MaxDataCount = cpu_to_le16(1000);
5764 pSMB->SetupCount = 1;
5765 pSMB->Reserved3 = 0;
5766 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5767 byte_count = 3 /* pad */ + params + count;
5768 pSMB->DataCount = cpu_to_le16(count);
5769 pSMB->ParameterCount = cpu_to_le16(params);
5770 pSMB->TotalDataCount = pSMB->DataCount;
5771 pSMB->TotalParameterCount = pSMB->ParameterCount;
5772 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5773 pSMB->DataOffset = cpu_to_le16(offset);
5774 pSMB->Fid = fid;
5775 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5776 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005777 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton6d22f092008-09-23 11:48:35 -04005778 pSMB->ByteCount = cpu_to_le16(byte_count);
5779 *data_offset = delete_file ? 1 : 0;
5780 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
5781 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005782 cFYI(1, "Send error in SetFileDisposition = %d", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005783
5784 return rc;
5785}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005786
5787int
Steve French96daf2b2011-05-27 04:34:02 +00005788CIFSSMBSetPathInfo(const int xid, struct cifs_tcon *tcon,
Jeff Layton6fc000e2008-08-02 07:26:12 -04005789 const char *fileName, const FILE_BASIC_INFO *data,
5790 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005791{
5792 TRANSACTION2_SPI_REQ *pSMB = NULL;
5793 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5794 int name_len;
5795 int rc = 0;
5796 int bytes_returned = 0;
5797 char *data_offset;
5798 __u16 params, param_offset, offset, byte_count, count;
5799
Joe Perchesb6b38f72010-04-21 03:50:45 +00005800 cFYI(1, "In SetTimes");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005801
5802SetTimesRetry:
5803 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5804 (void **) &pSMBr);
5805 if (rc)
5806 return rc;
5807
5808 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5809 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005810 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5811 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005812 name_len++; /* trailing null */
5813 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005814 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005815 name_len = strnlen(fileName, PATH_MAX);
5816 name_len++; /* trailing null */
5817 strncpy(pSMB->FileName, fileName, name_len);
5818 }
5819
5820 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005821 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005822 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005823 /* BB find max SMB PDU from sess structure BB */
5824 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005825 pSMB->MaxSetupCount = 0;
5826 pSMB->Reserved = 0;
5827 pSMB->Flags = 0;
5828 pSMB->Timeout = 0;
5829 pSMB->Reserved2 = 0;
5830 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005831 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005832 offset = param_offset + params;
5833 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5834 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5835 pSMB->DataOffset = cpu_to_le16(offset);
5836 pSMB->SetupCount = 1;
5837 pSMB->Reserved3 = 0;
5838 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5839 byte_count = 3 /* pad */ + params + count;
5840
5841 pSMB->DataCount = cpu_to_le16(count);
5842 pSMB->ParameterCount = cpu_to_le16(params);
5843 pSMB->TotalDataCount = pSMB->DataCount;
5844 pSMB->TotalParameterCount = pSMB->ParameterCount;
5845 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5846 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5847 else
5848 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5849 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005850 inc_rfc1001_len(pSMB, byte_count);
Steve French26f57362007-08-30 22:09:15 +00005851 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005852 pSMB->ByteCount = cpu_to_le16(byte_count);
5853 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5854 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005855 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005856 cFYI(1, "SetPathInfo (times) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005857
5858 cifs_buf_release(pSMB);
5859
5860 if (rc == -EAGAIN)
5861 goto SetTimesRetry;
5862
5863 return rc;
5864}
5865
5866/* Can not be used to set time stamps yet (due to old DOS time format) */
5867/* Can be used to set attributes */
5868#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5869 handling it anyway and NT4 was what we thought it would be needed for
5870 Do not delete it until we prove whether needed for Win9x though */
5871int
Steve French96daf2b2011-05-27 04:34:02 +00005872CIFSSMBSetAttrLegacy(int xid, struct cifs_tcon *tcon, char *fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005873 __u16 dos_attrs, const struct nls_table *nls_codepage)
5874{
5875 SETATTR_REQ *pSMB = NULL;
5876 SETATTR_RSP *pSMBr = NULL;
5877 int rc = 0;
5878 int bytes_returned;
5879 int name_len;
5880
Joe Perchesb6b38f72010-04-21 03:50:45 +00005881 cFYI(1, "In SetAttrLegacy");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005882
5883SetAttrLgcyRetry:
5884 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5885 (void **) &pSMBr);
5886 if (rc)
5887 return rc;
5888
5889 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5890 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005891 ConvertToUTF16((__le16 *) pSMB->fileName, fileName,
5892 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005893 name_len++; /* trailing null */
5894 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005895 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005896 name_len = strnlen(fileName, PATH_MAX);
5897 name_len++; /* trailing null */
5898 strncpy(pSMB->fileName, fileName, name_len);
5899 }
5900 pSMB->attr = cpu_to_le16(dos_attrs);
5901 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005902 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005903 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5904 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5905 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005906 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005907 cFYI(1, "Error in LegacySetAttr = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005908
5909 cifs_buf_release(pSMB);
5910
5911 if (rc == -EAGAIN)
5912 goto SetAttrLgcyRetry;
5913
5914 return rc;
5915}
5916#endif /* temporarily unneeded SetAttr legacy function */
5917
Jeff Layton654cf142009-07-09 20:02:49 -04005918static void
5919cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5920 const struct cifs_unix_set_info_args *args)
5921{
5922 u64 mode = args->mode;
5923
5924 /*
5925 * Samba server ignores set of file size to zero due to bugs in some
5926 * older clients, but we should be precise - we use SetFileSize to
5927 * set file size and do not want to truncate file size to zero
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005928 * accidentally as happened on one Samba server beta by putting
Jeff Layton654cf142009-07-09 20:02:49 -04005929 * zero instead of -1 here
5930 */
5931 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5932 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5933 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5934 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5935 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5936 data_offset->Uid = cpu_to_le64(args->uid);
5937 data_offset->Gid = cpu_to_le64(args->gid);
5938 /* better to leave device as zero when it is */
5939 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5940 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5941 data_offset->Permissions = cpu_to_le64(mode);
5942
5943 if (S_ISREG(mode))
5944 data_offset->Type = cpu_to_le32(UNIX_FILE);
5945 else if (S_ISDIR(mode))
5946 data_offset->Type = cpu_to_le32(UNIX_DIR);
5947 else if (S_ISLNK(mode))
5948 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5949 else if (S_ISCHR(mode))
5950 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5951 else if (S_ISBLK(mode))
5952 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5953 else if (S_ISFIFO(mode))
5954 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5955 else if (S_ISSOCK(mode))
5956 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5957}
5958
Linus Torvalds1da177e2005-04-16 15:20:36 -07005959int
Steve French96daf2b2011-05-27 04:34:02 +00005960CIFSSMBUnixSetFileInfo(const int xid, struct cifs_tcon *tcon,
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005961 const struct cifs_unix_set_info_args *args,
5962 u16 fid, u32 pid_of_opener)
5963{
5964 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5965 FILE_UNIX_BASIC_INFO *data_offset;
5966 int rc = 0;
5967 u16 params, param_offset, offset, byte_count, count;
5968
Joe Perchesb6b38f72010-04-21 03:50:45 +00005969 cFYI(1, "Set Unix Info (via SetFileInfo)");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005970 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5971
5972 if (rc)
5973 return rc;
5974
5975 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5976 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5977
5978 params = 6;
5979 pSMB->MaxSetupCount = 0;
5980 pSMB->Reserved = 0;
5981 pSMB->Flags = 0;
5982 pSMB->Timeout = 0;
5983 pSMB->Reserved2 = 0;
5984 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5985 offset = param_offset + params;
5986
5987 data_offset = (FILE_UNIX_BASIC_INFO *)
5988 ((char *)(&pSMB->hdr.Protocol) + offset);
5989 count = sizeof(FILE_UNIX_BASIC_INFO);
5990
5991 pSMB->MaxParameterCount = cpu_to_le16(2);
5992 /* BB find max SMB PDU from sess */
5993 pSMB->MaxDataCount = cpu_to_le16(1000);
5994 pSMB->SetupCount = 1;
5995 pSMB->Reserved3 = 0;
5996 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5997 byte_count = 3 /* pad */ + params + count;
5998 pSMB->DataCount = cpu_to_le16(count);
5999 pSMB->ParameterCount = cpu_to_le16(params);
6000 pSMB->TotalDataCount = pSMB->DataCount;
6001 pSMB->TotalParameterCount = pSMB->ParameterCount;
6002 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6003 pSMB->DataOffset = cpu_to_le16(offset);
6004 pSMB->Fid = fid;
6005 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6006 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006007 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006008 pSMB->ByteCount = cpu_to_le16(byte_count);
6009
6010 cifs_fill_unix_set_info(data_offset, args);
6011
6012 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
6013 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00006014 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006015
6016 /* Note: On -EAGAIN error only caller can retry on handle based calls
6017 since file handle passed in no longer valid */
6018
6019 return rc;
6020}
6021
6022int
Steve French96daf2b2011-05-27 04:34:02 +00006023CIFSSMBUnixSetPathInfo(const int xid, struct cifs_tcon *tcon, char *fileName,
Jeff Layton01ea95e2009-07-09 20:02:49 -04006024 const struct cifs_unix_set_info_args *args,
6025 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006026{
6027 TRANSACTION2_SPI_REQ *pSMB = NULL;
6028 TRANSACTION2_SPI_RSP *pSMBr = NULL;
6029 int name_len;
6030 int rc = 0;
6031 int bytes_returned = 0;
6032 FILE_UNIX_BASIC_INFO *data_offset;
6033 __u16 params, param_offset, offset, count, byte_count;
6034
Joe Perchesb6b38f72010-04-21 03:50:45 +00006035 cFYI(1, "In SetUID/GID/Mode");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006036setPermsRetry:
6037 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6038 (void **) &pSMBr);
6039 if (rc)
6040 return rc;
6041
6042 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6043 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006044 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
6045 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006046 name_len++; /* trailing null */
6047 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07006048 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006049 name_len = strnlen(fileName, PATH_MAX);
6050 name_len++; /* trailing null */
6051 strncpy(pSMB->FileName, fileName, name_len);
6052 }
6053
6054 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00006055 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006056 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006057 /* BB find max SMB PDU from sess structure BB */
6058 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006059 pSMB->MaxSetupCount = 0;
6060 pSMB->Reserved = 0;
6061 pSMB->Flags = 0;
6062 pSMB->Timeout = 0;
6063 pSMB->Reserved2 = 0;
6064 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006065 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006066 offset = param_offset + params;
6067 data_offset =
6068 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
6069 offset);
6070 memset(data_offset, 0, count);
6071 pSMB->DataOffset = cpu_to_le16(offset);
6072 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6073 pSMB->SetupCount = 1;
6074 pSMB->Reserved3 = 0;
6075 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6076 byte_count = 3 /* pad */ + params + count;
6077 pSMB->ParameterCount = cpu_to_le16(params);
6078 pSMB->DataCount = cpu_to_le16(count);
6079 pSMB->TotalParameterCount = pSMB->ParameterCount;
6080 pSMB->TotalDataCount = pSMB->DataCount;
6081 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6082 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006083 inc_rfc1001_len(pSMB, byte_count);
Steve French50c2f752007-07-13 00:33:32 +00006084
Jeff Layton654cf142009-07-09 20:02:49 -04006085 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006086
6087 pSMB->ByteCount = cpu_to_le16(byte_count);
6088 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6089 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006090 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00006091 cFYI(1, "SetPathInfo (perms) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006092
Steve French0d817bc2008-05-22 02:02:03 +00006093 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006094 if (rc == -EAGAIN)
6095 goto setPermsRetry;
6096 return rc;
6097}
6098
Linus Torvalds1da177e2005-04-16 15:20:36 -07006099#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05006100/*
6101 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
6102 * function used by listxattr and getxattr type calls. When ea_name is set,
6103 * it looks for that attribute name and stuffs that value into the EAData
6104 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
6105 * buffer. In both cases, the return value is either the length of the
6106 * resulting data or a negative error code. If EAData is a NULL pointer then
6107 * the data isn't copied to it, but the length is returned.
6108 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006109ssize_t
Steve French96daf2b2011-05-27 04:34:02 +00006110CIFSSMBQAllEAs(const int xid, struct cifs_tcon *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05006111 const unsigned char *searchName, const unsigned char *ea_name,
6112 char *EAData, size_t buf_size,
6113 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006114{
6115 /* BB assumes one setup word */
6116 TRANSACTION2_QPI_REQ *pSMB = NULL;
6117 TRANSACTION2_QPI_RSP *pSMBr = NULL;
6118 int rc = 0;
6119 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05006120 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006121 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00006122 struct fea *temp_fea;
6123 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006124 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006125 __u16 params, byte_count, data_offset;
Jeff Layton5980fc92011-07-28 12:48:26 -04006126 unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006127
Joe Perchesb6b38f72010-04-21 03:50:45 +00006128 cFYI(1, "In Query All EAs path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006129QAllEAsRetry:
6130 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6131 (void **) &pSMBr);
6132 if (rc)
6133 return rc;
6134
6135 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05006136 list_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006137 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
6138 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05006139 list_len++; /* trailing null */
6140 list_len *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006141 } else { /* BB improve the check for buffer overruns BB */
Jeff Layton6e462b92010-02-10 16:18:26 -05006142 list_len = strnlen(searchName, PATH_MAX);
6143 list_len++; /* trailing null */
6144 strncpy(pSMB->FileName, searchName, list_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006145 }
6146
Jeff Layton6e462b92010-02-10 16:18:26 -05006147 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006148 pSMB->TotalDataCount = 0;
6149 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006150 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05006151 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006152 pSMB->MaxSetupCount = 0;
6153 pSMB->Reserved = 0;
6154 pSMB->Flags = 0;
6155 pSMB->Timeout = 0;
6156 pSMB->Reserved2 = 0;
6157 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00006158 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006159 pSMB->DataCount = 0;
6160 pSMB->DataOffset = 0;
6161 pSMB->SetupCount = 1;
6162 pSMB->Reserved3 = 0;
6163 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
6164 byte_count = params + 1 /* pad */ ;
6165 pSMB->TotalParameterCount = cpu_to_le16(params);
6166 pSMB->ParameterCount = pSMB->TotalParameterCount;
6167 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
6168 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006169 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006170 pSMB->ByteCount = cpu_to_le16(byte_count);
6171
6172 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6173 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6174 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006175 cFYI(1, "Send error in QueryAllEAs = %d", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05006176 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006177 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006178
6179
6180 /* BB also check enough total bytes returned */
6181 /* BB we need to improve the validity checking
6182 of these trans2 responses */
6183
6184 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Jeff Layton820a8032011-05-04 08:05:26 -04006185 if (rc || get_bcc(&pSMBr->hdr) < 4) {
Jeff Laytonf0d38682010-02-10 16:18:26 -05006186 rc = -EIO; /* bad smb */
6187 goto QAllEAsOut;
6188 }
6189
6190 /* check that length of list is not more than bcc */
6191 /* check that each entry does not go beyond length
6192 of list */
6193 /* check that each element of each entry does not
6194 go beyond end of list */
6195 /* validate_trans2_offsets() */
6196 /* BB check if start of smb + data_offset > &bcc+ bcc */
6197
6198 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
6199 ea_response_data = (struct fealist *)
6200 (((char *) &pSMBr->hdr.Protocol) + data_offset);
6201
Jeff Layton6e462b92010-02-10 16:18:26 -05006202 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesb6b38f72010-04-21 03:50:45 +00006203 cFYI(1, "ea length %d", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05006204 if (list_len <= 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006205 cFYI(1, "empty EA list returned from server");
Jeff Laytonf0d38682010-02-10 16:18:26 -05006206 goto QAllEAsOut;
6207 }
6208
Jeff Layton0cd126b2010-02-10 16:18:26 -05006209 /* make sure list_len doesn't go past end of SMB */
Jeff Layton690c5222011-01-20 13:36:51 -05006210 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
Jeff Layton0cd126b2010-02-10 16:18:26 -05006211 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006212 cFYI(1, "EA list appears to go beyond SMB");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006213 rc = -EIO;
6214 goto QAllEAsOut;
6215 }
6216
Jeff Laytonf0d38682010-02-10 16:18:26 -05006217 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05006218 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006219 temp_fea = ea_response_data->list;
6220 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05006221 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00006222 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006223 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006224
Jeff Layton6e462b92010-02-10 16:18:26 -05006225 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006226 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006227 /* make sure we can read name_len and value_len */
6228 if (list_len < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006229 cFYI(1, "EA entry goes beyond length of list");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006230 rc = -EIO;
6231 goto QAllEAsOut;
6232 }
6233
6234 name_len = temp_fea->name_len;
6235 value_len = le16_to_cpu(temp_fea->value_len);
6236 list_len -= name_len + 1 + value_len;
6237 if (list_len < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006238 cFYI(1, "EA entry goes beyond length of list");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006239 rc = -EIO;
6240 goto QAllEAsOut;
6241 }
6242
Jeff Layton31c05192010-02-10 16:18:26 -05006243 if (ea_name) {
Jeff Layton91d065c2011-07-26 18:23:47 -04006244 if (ea_name_len == name_len &&
Jeff Laytonac423442011-10-11 06:41:32 -04006245 memcmp(ea_name, temp_ptr, name_len) == 0) {
Jeff Layton31c05192010-02-10 16:18:26 -05006246 temp_ptr += name_len + 1;
6247 rc = value_len;
6248 if (buf_size == 0)
6249 goto QAllEAsOut;
6250 if ((size_t)value_len > buf_size) {
6251 rc = -ERANGE;
6252 goto QAllEAsOut;
6253 }
6254 memcpy(EAData, temp_ptr, value_len);
6255 goto QAllEAsOut;
6256 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006257 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05006258 /* account for prefix user. and trailing null */
6259 rc += (5 + 1 + name_len);
6260 if (rc < (int) buf_size) {
6261 memcpy(EAData, "user.", 5);
6262 EAData += 5;
6263 memcpy(EAData, temp_ptr, name_len);
6264 EAData += name_len;
6265 /* null terminate name */
6266 *EAData = 0;
6267 ++EAData;
6268 } else if (buf_size == 0) {
6269 /* skip copy - calc size only */
6270 } else {
6271 /* stop before overrun buffer */
6272 rc = -ERANGE;
6273 break;
6274 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006275 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05006276 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006277 temp_fea = (struct fea *)temp_ptr;
6278 }
6279
Jeff Layton31c05192010-02-10 16:18:26 -05006280 /* didn't find the named attribute */
6281 if (ea_name)
6282 rc = -ENODATA;
6283
Jeff Laytonf0d38682010-02-10 16:18:26 -05006284QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00006285 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006286 if (rc == -EAGAIN)
6287 goto QAllEAsRetry;
6288
6289 return (ssize_t)rc;
6290}
6291
Linus Torvalds1da177e2005-04-16 15:20:36 -07006292int
Steve French96daf2b2011-05-27 04:34:02 +00006293CIFSSMBSetEA(const int xid, struct cifs_tcon *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00006294 const char *ea_name, const void *ea_value,
6295 const __u16 ea_value_len, const struct nls_table *nls_codepage,
6296 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006297{
6298 struct smb_com_transaction2_spi_req *pSMB = NULL;
6299 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
6300 struct fealist *parm_data;
6301 int name_len;
6302 int rc = 0;
6303 int bytes_returned = 0;
6304 __u16 params, param_offset, byte_count, offset, count;
6305
Joe Perchesb6b38f72010-04-21 03:50:45 +00006306 cFYI(1, "In SetEA");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006307SetEARetry:
6308 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6309 (void **) &pSMBr);
6310 if (rc)
6311 return rc;
6312
6313 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6314 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006315 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
6316 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006317 name_len++; /* trailing null */
6318 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00006319 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006320 name_len = strnlen(fileName, PATH_MAX);
6321 name_len++; /* trailing null */
6322 strncpy(pSMB->FileName, fileName, name_len);
6323 }
6324
6325 params = 6 + name_len;
6326
6327 /* done calculating parms using name_len of file name,
6328 now use name_len to calculate length of ea name
6329 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00006330 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006331 name_len = 0;
6332 else
Steve French50c2f752007-07-13 00:33:32 +00006333 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006334
Steve Frenchdae5dbd2007-12-30 23:49:57 +00006335 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006336 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006337 /* BB find max SMB PDU from sess */
6338 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006339 pSMB->MaxSetupCount = 0;
6340 pSMB->Reserved = 0;
6341 pSMB->Flags = 0;
6342 pSMB->Timeout = 0;
6343 pSMB->Reserved2 = 0;
6344 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006345 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006346 offset = param_offset + params;
6347 pSMB->InformationLevel =
6348 cpu_to_le16(SMB_SET_FILE_EA);
6349
6350 parm_data =
6351 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
6352 offset);
6353 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6354 pSMB->DataOffset = cpu_to_le16(offset);
6355 pSMB->SetupCount = 1;
6356 pSMB->Reserved3 = 0;
6357 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6358 byte_count = 3 /* pad */ + params + count;
6359 pSMB->DataCount = cpu_to_le16(count);
6360 parm_data->list_len = cpu_to_le32(count);
6361 parm_data->list[0].EA_flags = 0;
6362 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08006363 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006364 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00006365 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00006366 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006367 parm_data->list[0].name[name_len] = 0;
6368 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
6369 /* caller ensures that ea_value_len is less than 64K but
6370 we need to ensure that it fits within the smb */
6371
Steve French50c2f752007-07-13 00:33:32 +00006372 /*BB add length check to see if it would fit in
6373 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00006374 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
6375 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00006376 memcpy(parm_data->list[0].name+name_len+1,
6377 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006378
6379 pSMB->TotalDataCount = pSMB->DataCount;
6380 pSMB->ParameterCount = cpu_to_le16(params);
6381 pSMB->TotalParameterCount = pSMB->ParameterCount;
6382 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006383 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006384 pSMB->ByteCount = cpu_to_le16(byte_count);
6385 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6386 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006387 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00006388 cFYI(1, "SetPathInfo (EA) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006389
6390 cifs_buf_release(pSMB);
6391
6392 if (rc == -EAGAIN)
6393 goto SetEARetry;
6394
6395 return rc;
6396}
Linus Torvalds1da177e2005-04-16 15:20:36 -07006397#endif
Steve French0eff0e22011-02-24 05:39:23 +00006398
6399#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */
6400/*
6401 * Years ago the kernel added a "dnotify" function for Samba server,
6402 * to allow network clients (such as Windows) to display updated
6403 * lists of files in directory listings automatically when
6404 * files are added by one user when another user has the
6405 * same directory open on their desktop. The Linux cifs kernel
6406 * client hooked into the kernel side of this interface for
6407 * the same reason, but ironically when the VFS moved from
6408 * "dnotify" to "inotify" it became harder to plug in Linux
6409 * network file system clients (the most obvious use case
6410 * for notify interfaces is when multiple users can update
6411 * the contents of the same directory - exactly what network
6412 * file systems can do) although the server (Samba) could
6413 * still use it. For the short term we leave the worker
6414 * function ifdeffed out (below) until inotify is fixed
6415 * in the VFS to make it easier to plug in network file
6416 * system clients. If inotify turns out to be permanently
6417 * incompatible for network fs clients, we could instead simply
6418 * expose this config flag by adding a future cifs (and smb2) notify ioctl.
6419 */
Steve French96daf2b2011-05-27 04:34:02 +00006420int CIFSSMBNotify(const int xid, struct cifs_tcon *tcon,
Steve French0eff0e22011-02-24 05:39:23 +00006421 const int notify_subdirs, const __u16 netfid,
6422 __u32 filter, struct file *pfile, int multishot,
6423 const struct nls_table *nls_codepage)
6424{
6425 int rc = 0;
6426 struct smb_com_transaction_change_notify_req *pSMB = NULL;
6427 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
6428 struct dir_notify_req *dnotify_req;
6429 int bytes_returned;
6430
6431 cFYI(1, "In CIFSSMBNotify for file handle %d", (int)netfid);
6432 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
6433 (void **) &pSMBr);
6434 if (rc)
6435 return rc;
6436
6437 pSMB->TotalParameterCount = 0 ;
6438 pSMB->TotalDataCount = 0;
6439 pSMB->MaxParameterCount = cpu_to_le32(2);
Jeff Laytonc974bef2011-10-11 06:41:32 -04006440 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Steve French0eff0e22011-02-24 05:39:23 +00006441 pSMB->MaxSetupCount = 4;
6442 pSMB->Reserved = 0;
6443 pSMB->ParameterOffset = 0;
6444 pSMB->DataCount = 0;
6445 pSMB->DataOffset = 0;
6446 pSMB->SetupCount = 4; /* single byte does not need le conversion */
6447 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
6448 pSMB->ParameterCount = pSMB->TotalParameterCount;
6449 if (notify_subdirs)
6450 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
6451 pSMB->Reserved2 = 0;
6452 pSMB->CompletionFilter = cpu_to_le32(filter);
6453 pSMB->Fid = netfid; /* file handle always le */
6454 pSMB->ByteCount = 0;
6455
6456 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6457 (struct smb_hdr *)pSMBr, &bytes_returned,
6458 CIFS_ASYNC_OP);
6459 if (rc) {
6460 cFYI(1, "Error in Notify = %d", rc);
6461 } else {
6462 /* Add file to outstanding requests */
6463 /* BB change to kmem cache alloc */
6464 dnotify_req = kmalloc(
6465 sizeof(struct dir_notify_req),
6466 GFP_KERNEL);
6467 if (dnotify_req) {
6468 dnotify_req->Pid = pSMB->hdr.Pid;
6469 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
6470 dnotify_req->Mid = pSMB->hdr.Mid;
6471 dnotify_req->Tid = pSMB->hdr.Tid;
6472 dnotify_req->Uid = pSMB->hdr.Uid;
6473 dnotify_req->netfid = netfid;
6474 dnotify_req->pfile = pfile;
6475 dnotify_req->filter = filter;
6476 dnotify_req->multishot = multishot;
6477 spin_lock(&GlobalMid_Lock);
6478 list_add_tail(&dnotify_req->lhead,
6479 &GlobalDnotifyReqList);
6480 spin_unlock(&GlobalMid_Lock);
6481 } else
6482 rc = -ENOMEM;
6483 }
6484 cifs_buf_release(pSMB);
6485 return rc;
6486}
6487#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */