blob: 6600aa2d2ef38a38c228a1cd26cbeae2ea2b6b06 [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);
Steve French254e55e2006-06-04 05:53:15 +0000461 server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
Jeff Laytonc974bef2011-10-11 06:41:32 -0400462 server->maxBuf = le16_to_cpu(rsp->MaxBufSize);
Steve Frencheca6acf2009-02-20 05:43:09 +0000463 server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
Steve French254e55e2006-06-04 05:53:15 +0000464 /* even though we do not use raw we might as well set this
465 accurately, in case we ever find a need for it */
Steve French790fe572007-07-07 19:25:05 +0000466 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
Steve Frencheca6acf2009-02-20 05:43:09 +0000467 server->max_rw = 0xFF00;
Steve French254e55e2006-06-04 05:53:15 +0000468 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
469 } else {
Steve Frencheca6acf2009-02-20 05:43:09 +0000470 server->max_rw = 0;/* do not need to use raw anyway */
Steve French254e55e2006-06-04 05:53:15 +0000471 server->capabilities = CAP_MPX_MODE;
472 }
Steve Frenchb815f1e52006-10-02 05:53:29 +0000473 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
Steve French1a70d652006-10-02 05:59:18 +0000474 if (tmp == -1) {
Steve French25ee4a92006-09-30 00:54:23 +0000475 /* OS/2 often does not set timezone therefore
476 * we must use server time to calc time zone.
Steve Frenchb815f1e52006-10-02 05:53:29 +0000477 * Could deviate slightly from the right zone.
478 * Smallest defined timezone difference is 15 minutes
479 * (i.e. Nepal). Rounding up/down is done to match
480 * this requirement.
Steve French25ee4a92006-09-30 00:54:23 +0000481 */
Steve Frenchb815f1e52006-10-02 05:53:29 +0000482 int val, seconds, remain, result;
Steve French25ee4a92006-09-30 00:54:23 +0000483 struct timespec ts, utc;
484 utc = CURRENT_TIME;
Jeff Laytonc4a2c082009-05-27 09:37:33 -0400485 ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
486 rsp->SrvTime.Time, 0);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000487 cFYI(1, "SrvTime %d sec since 1970 (utc: %d) diff: %d",
Steve French50c2f752007-07-13 00:33:32 +0000488 (int)ts.tv_sec, (int)utc.tv_sec,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000489 (int)(utc.tv_sec - ts.tv_sec));
Steve Frenchb815f1e52006-10-02 05:53:29 +0000490 val = (int)(utc.tv_sec - ts.tv_sec);
Andre Haupt8594c152007-08-30 20:18:41 +0000491 seconds = abs(val);
Steve French947a5062006-10-02 05:55:25 +0000492 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
Steve Frenchb815f1e52006-10-02 05:53:29 +0000493 remain = seconds % MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000494 if (remain >= (MIN_TZ_ADJ / 2))
Steve Frenchb815f1e52006-10-02 05:53:29 +0000495 result += MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000496 if (val < 0)
Steve Frenchad7a2922008-02-07 23:25:02 +0000497 result = -result;
Steve Frenchb815f1e52006-10-02 05:53:29 +0000498 server->timeAdj = result;
Steve French25ee4a92006-09-30 00:54:23 +0000499 } else {
Steve Frenchb815f1e52006-10-02 05:53:29 +0000500 server->timeAdj = (int)tmp;
501 server->timeAdj *= 60; /* also in seconds */
Steve French25ee4a92006-09-30 00:54:23 +0000502 }
Joe Perchesb6b38f72010-04-21 03:50:45 +0000503 cFYI(1, "server->timeAdj: %d seconds", server->timeAdj);
Steve French25ee4a92006-09-30 00:54:23 +0000504
Steve French39798772006-05-31 22:40:51 +0000505
Steve French254e55e2006-06-04 05:53:15 +0000506 /* BB get server time for time conversions and add
Steve French50c2f752007-07-13 00:33:32 +0000507 code to use it and timezone since this is not UTC */
Steve French39798772006-05-31 22:40:51 +0000508
Steve French50c2f752007-07-13 00:33:32 +0000509 if (rsp->EncryptionKeyLength ==
Steve French25ee4a92006-09-30 00:54:23 +0000510 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500511 memcpy(ses->server->cryptkey, rsp->EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000512 CIFS_CRYPTO_KEY_SIZE);
Steve French96daf2b2011-05-27 04:34:02 +0000513 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
Steve French254e55e2006-06-04 05:53:15 +0000514 rc = -EIO; /* need cryptkey unless plain text */
515 goto neg_err_exit;
516 }
Steve French39798772006-05-31 22:40:51 +0000517
Steve Frenchf19159d2010-04-21 04:12:10 +0000518 cFYI(1, "LANMAN negotiated");
Steve French254e55e2006-06-04 05:53:15 +0000519 /* we will not end up setting signing flags - as no signing
520 was in LANMAN and server did not return the flags on */
521 goto signing_check;
Steve French7c7b25b2006-06-01 19:20:10 +0000522#else /* weak security disabled */
Steve French790fe572007-07-07 19:25:05 +0000523 } else if (pSMBr->hdr.WordCount == 13) {
Steve Frenchf19159d2010-04-21 04:12:10 +0000524 cERROR(1, "mount failed, cifs module not built "
525 "with CIFS_WEAK_PW_HASH support");
Dan Carpenter8212cf72010-03-15 11:22:26 +0300526 rc = -EOPNOTSUPP;
Steve French7c7b25b2006-06-01 19:20:10 +0000527#endif /* WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000528 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000529 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000530 /* unknown wct */
531 rc = -EOPNOTSUPP;
532 goto neg_err_exit;
533 }
534 /* else wct == 17 NTLM */
Steve French96daf2b2011-05-27 04:34:02 +0000535 server->sec_mode = pSMBr->SecurityMode;
536 if ((server->sec_mode & SECMODE_USER) == 0)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000537 cFYI(1, "share mode security");
Steve French39798772006-05-31 22:40:51 +0000538
Steve French96daf2b2011-05-27 04:34:02 +0000539 if ((server->sec_mode & SECMODE_PW_ENCRYPT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000540#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French750d1152006-06-27 06:28:30 +0000541 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000542#endif /* CIFS_WEAK_PW_HASH */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000543 cERROR(1, "Server requests plain text password"
544 " but client support disabled");
Steve French9312f672006-06-04 22:21:07 +0000545
Steve French790fe572007-07-07 19:25:05 +0000546 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
Steve French254e55e2006-06-04 05:53:15 +0000547 server->secType = NTLMv2;
Steve French790fe572007-07-07 19:25:05 +0000548 else if (secFlags & CIFSSEC_MAY_NTLM)
Steve French254e55e2006-06-04 05:53:15 +0000549 server->secType = NTLM;
Steve French790fe572007-07-07 19:25:05 +0000550 else if (secFlags & CIFSSEC_MAY_NTLMV2)
Steve Frenchf40c5622006-06-28 00:13:38 +0000551 server->secType = NTLMv2;
Steve Frencha0136892007-10-04 20:05:09 +0000552 else if (secFlags & CIFSSEC_MAY_KRB5)
553 server->secType = Kerberos;
Steve Frenchac683922009-05-06 04:16:04 +0000554 else if (secFlags & CIFSSEC_MAY_NTLMSSP)
Steve Frenchf46c7232009-06-25 03:04:20 +0000555 server->secType = RawNTLMSSP;
Steve Frencha0136892007-10-04 20:05:09 +0000556 else if (secFlags & CIFSSEC_MAY_LANMAN)
557 server->secType = LANMAN;
Steve Frencha0136892007-10-04 20:05:09 +0000558 else {
559 rc = -EOPNOTSUPP;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000560 cERROR(1, "Invalid security type");
Steve Frencha0136892007-10-04 20:05:09 +0000561 goto neg_err_exit;
562 }
563 /* else ... any others ...? */
Steve French7c7b25b2006-06-01 19:20:10 +0000564
Steve French254e55e2006-06-04 05:53:15 +0000565 /* one byte, so no need to convert this or EncryptionKeyLen from
566 little endian */
567 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
568 /* probably no need to store and check maxvcs */
Jeff Laytonc974bef2011-10-11 06:41:32 -0400569 server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize);
Steve Frencheca6acf2009-02-20 05:43:09 +0000570 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000571 cFYI(DBG2, "Max buf = %d", ses->server->maxBuf);
Steve French254e55e2006-06-04 05:53:15 +0000572 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e52006-10-02 05:53:29 +0000573 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
574 server->timeAdj *= 60;
Steve French254e55e2006-06-04 05:53:15 +0000575 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500576 memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000577 CIFS_CRYPTO_KEY_SIZE);
Steve French07cc6cf2011-05-27 04:12:29 +0000578 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC ||
579 server->capabilities & CAP_EXTENDED_SECURITY) &&
580 (pSMBr->EncryptionKeyLength == 0)) {
Steve French254e55e2006-06-04 05:53:15 +0000581 /* decode security blob */
Jeff Layton820a8032011-05-04 08:05:26 -0400582 count = get_bcc(&pSMBr->hdr);
Jeff Laytone187e442007-10-16 17:10:44 +0000583 if (count < 16) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 rc = -EIO;
Jeff Laytone187e442007-10-16 17:10:44 +0000585 goto neg_err_exit;
586 }
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530587 spin_lock(&cifs_tcp_ses_lock);
Jeff Laytone7ddee92008-11-14 13:44:38 -0500588 if (server->srv_count > 1) {
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530589 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000590 if (memcmp(server->server_GUID,
591 pSMBr->u.extended_response.
592 GUID, 16) != 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000593 cFYI(1, "server UID changed");
Steve French254e55e2006-06-04 05:53:15 +0000594 memcpy(server->server_GUID,
Jeff Laytone187e442007-10-16 17:10:44 +0000595 pSMBr->u.extended_response.GUID,
596 16);
597 }
Jeff Laytone7ddee92008-11-14 13:44:38 -0500598 } else {
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530599 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000600 memcpy(server->server_GUID,
601 pSMBr->u.extended_response.GUID, 16);
Jeff Laytone7ddee92008-11-14 13:44:38 -0500602 }
Jeff Laytone187e442007-10-16 17:10:44 +0000603
604 if (count == 16) {
605 server->secType = RawNTLMSSP;
Steve French254e55e2006-06-04 05:53:15 +0000606 } else {
607 rc = decode_negTokenInit(pSMBr->u.extended_response.
Jeff Layton26efa0b2010-04-24 07:57:49 -0400608 SecurityBlob, count - 16,
609 server);
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000610 if (rc == 1)
Jeff Laytone5459372007-11-03 05:11:06 +0000611 rc = 0;
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000612 else
Steve French254e55e2006-06-04 05:53:15 +0000613 rc = -EINVAL;
Shirish Pargaonkar2b149f12010-09-18 22:02:18 -0500614 if (server->secType == Kerberos) {
615 if (!server->sec_kerberos &&
616 !server->sec_mskerberos)
617 rc = -EOPNOTSUPP;
618 } else if (server->secType == RawNTLMSSP) {
619 if (!server->sec_ntlmssp)
620 rc = -EOPNOTSUPP;
621 } else
622 rc = -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 }
Steve French96daf2b2011-05-27 04:34:02 +0000624 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
Steve French07cc6cf2011-05-27 04:12:29 +0000625 rc = -EIO; /* no crypt key only if plain text pwd */
626 goto neg_err_exit;
Steve French254e55e2006-06-04 05:53:15 +0000627 } else
628 server->capabilities &= ~CAP_EXTENDED_SECURITY;
629
Steve French6344a422006-06-12 04:18:35 +0000630#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French254e55e2006-06-04 05:53:15 +0000631signing_check:
Steve French6344a422006-06-12 04:18:35 +0000632#endif
Steve French762e5ab2007-06-28 18:41:42 +0000633 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
634 /* MUST_SIGN already includes the MAY_SIGN FLAG
635 so if this is zero it means that signing is disabled */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000636 cFYI(1, "Signing disabled");
Steve French96daf2b2011-05-27 04:34:02 +0000637 if (server->sec_mode & SECMODE_SIGN_REQUIRED) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000638 cERROR(1, "Server requires "
Jeff Layton7111d212007-10-16 16:50:25 +0000639 "packet signing to be enabled in "
Joe Perchesb6b38f72010-04-21 03:50:45 +0000640 "/proc/fs/cifs/SecurityFlags.");
Steve Frenchabb63d62007-10-18 02:58:40 +0000641 rc = -EOPNOTSUPP;
642 }
Steve French96daf2b2011-05-27 04:34:02 +0000643 server->sec_mode &=
Steve French254e55e2006-06-04 05:53:15 +0000644 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Steve French762e5ab2007-06-28 18:41:42 +0000645 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
646 /* signing required */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000647 cFYI(1, "Must sign - secFlags 0x%x", secFlags);
Steve French96daf2b2011-05-27 04:34:02 +0000648 if ((server->sec_mode &
Steve French762e5ab2007-06-28 18:41:42 +0000649 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000650 cERROR(1, "signing required but server lacks support");
Jeff38c10a12007-07-06 21:10:07 +0000651 rc = -EOPNOTSUPP;
Steve French762e5ab2007-06-28 18:41:42 +0000652 } else
Steve French96daf2b2011-05-27 04:34:02 +0000653 server->sec_mode |= SECMODE_SIGN_REQUIRED;
Steve French762e5ab2007-06-28 18:41:42 +0000654 } else {
655 /* signing optional ie CIFSSEC_MAY_SIGN */
Steve French96daf2b2011-05-27 04:34:02 +0000656 if ((server->sec_mode & SECMODE_SIGN_REQUIRED) == 0)
657 server->sec_mode &=
Steve French254e55e2006-06-04 05:53:15 +0000658 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 }
Steve French50c2f752007-07-13 00:33:32 +0000660
661neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700662 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000663
Joe Perchesb6b38f72010-04-21 03:50:45 +0000664 cFYI(1, "negprot rc %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 return rc;
666}
667
668int
Steve French96daf2b2011-05-27 04:34:02 +0000669CIFSSMBTDis(const int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670{
671 struct smb_hdr *smb_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673
Joe Perchesb6b38f72010-04-21 03:50:45 +0000674 cFYI(1, "In tree disconnect");
Jeff Laytonf1987b42008-11-15 11:12:47 -0500675
676 /* BB: do we need to check this? These should never be NULL. */
677 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
678 return -EIO;
679
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 /*
Jeff Laytonf1987b42008-11-15 11:12:47 -0500681 * No need to return error on this operation if tid invalidated and
682 * closed on server already e.g. due to tcp session crashing. Also,
683 * the tcon is no longer on the list, so no need to take lock before
684 * checking this.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 */
Steve French268875b2009-06-25 00:29:21 +0000686 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
Steve French50c2f752007-07-13 00:33:32 +0000687 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688
Steve French50c2f752007-07-13 00:33:32 +0000689 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700690 (void **)&smb_buffer);
Jeff Laytonf1987b42008-11-15 11:12:47 -0500691 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 return rc;
Steve French133672e2007-11-13 22:41:37 +0000693
694 rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000696 cFYI(1, "Tree disconnect failed %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697
Steve French50c2f752007-07-13 00:33:32 +0000698 /* No need to return error on this operation if tid invalidated and
Jeff Laytonf1987b42008-11-15 11:12:47 -0500699 closed on server already e.g. due to tcp session crashing */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 if (rc == -EAGAIN)
701 rc = 0;
702
703 return rc;
704}
705
Jeff Layton766fdbb2011-01-11 07:24:21 -0500706/*
707 * This is a no-op for now. We're not really interested in the reply, but
708 * rather in the fact that the server sent one and that server->lstrp
709 * gets updated.
710 *
711 * FIXME: maybe we should consider checking that the reply matches request?
712 */
713static void
714cifs_echo_callback(struct mid_q_entry *mid)
715{
716 struct TCP_Server_Info *server = mid->callback_data;
717
718 DeleteMidQEntry(mid);
719 atomic_dec(&server->inFlight);
720 wake_up(&server->request_q);
721}
722
723int
724CIFSSMBEcho(struct TCP_Server_Info *server)
725{
726 ECHO_REQ *smb;
727 int rc = 0;
Jeff Laytonfcc31cb2011-05-19 16:22:53 -0400728 struct kvec iov;
Jeff Layton766fdbb2011-01-11 07:24:21 -0500729
730 cFYI(1, "In echo request");
731
732 rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
733 if (rc)
734 return rc;
735
736 /* set up echo request */
Steve French5443d132011-03-13 05:08:25 +0000737 smb->hdr.Tid = 0xffff;
Jeff Layton99d86c82011-01-20 21:19:25 -0500738 smb->hdr.WordCount = 1;
739 put_unaligned_le16(1, &smb->EchoCount);
Jeff Layton820a8032011-05-04 08:05:26 -0400740 put_bcc(1, &smb->hdr);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500741 smb->Data[0] = 'a';
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000742 inc_rfc1001_len(smb, 3);
Jeff Laytonfcc31cb2011-05-19 16:22:53 -0400743 iov.iov_base = smb;
744 iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
Jeff Layton766fdbb2011-01-11 07:24:21 -0500745
Jeff Layton44d22d82011-10-19 15:29:49 -0400746 rc = cifs_call_async(server, &iov, 1, NULL, cifs_echo_callback,
747 server, true);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500748 if (rc)
749 cFYI(1, "Echo request failed: %d", rc);
750
751 cifs_small_buf_release(smb);
752
753 return rc;
754}
755
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756int
Steve French96daf2b2011-05-27 04:34:02 +0000757CIFSSMBLogoff(const int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 LOGOFF_ANDX_REQ *pSMB;
760 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761
Joe Perchesb6b38f72010-04-21 03:50:45 +0000762 cFYI(1, "In SMBLogoff for session disconnect");
Jeff Layton14fbf502008-11-14 13:53:46 -0500763
764 /*
765 * BB: do we need to check validity of ses and server? They should
766 * always be valid since we have an active reference. If not, that
767 * should probably be a BUG()
768 */
769 if (!ses || !ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 return -EIO;
771
Steve Frenchd7b619c2010-02-25 05:36:46 +0000772 mutex_lock(&ses->session_mutex);
Steve French3b795212008-11-13 19:45:32 +0000773 if (ses->need_reconnect)
774 goto session_already_dead; /* no need to send SMBlogoff if uid
775 already closed due to reconnect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
777 if (rc) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000778 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 return rc;
780 }
781
Steve French3b795212008-11-13 19:45:32 +0000782 pSMB->hdr.Mid = GetNextMid(ses->server);
Steve French1982c342005-08-17 12:38:22 -0700783
Steve French96daf2b2011-05-27 04:34:02 +0000784 if (ses->server->sec_mode &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
786 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787
788 pSMB->hdr.Uid = ses->Suid;
789
790 pSMB->AndXCommand = 0xFF;
Steve French133672e2007-11-13 22:41:37 +0000791 rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
Steve French3b795212008-11-13 19:45:32 +0000792session_already_dead:
Steve Frenchd7b619c2010-02-25 05:36:46 +0000793 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794
795 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000796 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797 error */
798 if (rc == -EAGAIN)
799 rc = 0;
800 return rc;
801}
802
803int
Steve French96daf2b2011-05-27 04:34:02 +0000804CIFSPOSIXDelFile(const int xid, struct cifs_tcon *tcon, const char *fileName,
Steve French2d785a52007-07-15 01:48:57 +0000805 __u16 type, const struct nls_table *nls_codepage, int remap)
806{
807 TRANSACTION2_SPI_REQ *pSMB = NULL;
808 TRANSACTION2_SPI_RSP *pSMBr = NULL;
809 struct unlink_psx_rq *pRqD;
810 int name_len;
811 int rc = 0;
812 int bytes_returned = 0;
813 __u16 params, param_offset, offset, byte_count;
814
Joe Perchesb6b38f72010-04-21 03:50:45 +0000815 cFYI(1, "In POSIX delete");
Steve French2d785a52007-07-15 01:48:57 +0000816PsxDelete:
817 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
818 (void **) &pSMBr);
819 if (rc)
820 return rc;
821
822 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
823 name_len =
824 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
825 PATH_MAX, nls_codepage, remap);
826 name_len++; /* trailing null */
827 name_len *= 2;
828 } else { /* BB add path length overrun check */
829 name_len = strnlen(fileName, PATH_MAX);
830 name_len++; /* trailing null */
831 strncpy(pSMB->FileName, fileName, name_len);
832 }
833
834 params = 6 + name_len;
835 pSMB->MaxParameterCount = cpu_to_le16(2);
836 pSMB->MaxDataCount = 0; /* BB double check this with jra */
837 pSMB->MaxSetupCount = 0;
838 pSMB->Reserved = 0;
839 pSMB->Flags = 0;
840 pSMB->Timeout = 0;
841 pSMB->Reserved2 = 0;
842 param_offset = offsetof(struct smb_com_transaction2_spi_req,
843 InformationLevel) - 4;
844 offset = param_offset + params;
845
846 /* Setup pointer to Request Data (inode type) */
847 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
848 pRqD->type = cpu_to_le16(type);
849 pSMB->ParameterOffset = cpu_to_le16(param_offset);
850 pSMB->DataOffset = cpu_to_le16(offset);
851 pSMB->SetupCount = 1;
852 pSMB->Reserved3 = 0;
853 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
854 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
855
856 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
857 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
858 pSMB->ParameterCount = cpu_to_le16(params);
859 pSMB->TotalParameterCount = pSMB->ParameterCount;
860 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
861 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000862 inc_rfc1001_len(pSMB, byte_count);
Steve French2d785a52007-07-15 01:48:57 +0000863 pSMB->ByteCount = cpu_to_le16(byte_count);
864 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
865 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000866 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000867 cFYI(1, "Posix delete returned %d", rc);
Steve French2d785a52007-07-15 01:48:57 +0000868 cifs_buf_release(pSMB);
869
870 cifs_stats_inc(&tcon->num_deletes);
871
872 if (rc == -EAGAIN)
873 goto PsxDelete;
874
875 return rc;
876}
877
878int
Steve French96daf2b2011-05-27 04:34:02 +0000879CIFSSMBDelFile(const int xid, struct cifs_tcon *tcon, const char *fileName,
Steve French737b7582005-04-28 22:41:06 -0700880 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881{
882 DELETE_FILE_REQ *pSMB = NULL;
883 DELETE_FILE_RSP *pSMBr = NULL;
884 int rc = 0;
885 int bytes_returned;
886 int name_len;
887
888DelFileRetry:
889 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
890 (void **) &pSMBr);
891 if (rc)
892 return rc;
893
894 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
895 name_len =
Steve French50c2f752007-07-13 00:33:32 +0000896 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
Steve French737b7582005-04-28 22:41:06 -0700897 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 name_len++; /* trailing null */
899 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700900 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 name_len = strnlen(fileName, PATH_MAX);
902 name_len++; /* trailing null */
903 strncpy(pSMB->fileName, fileName, name_len);
904 }
905 pSMB->SearchAttributes =
906 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
907 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000908 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 pSMB->ByteCount = cpu_to_le16(name_len + 1);
910 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
911 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700912 cifs_stats_inc(&tcon->num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000913 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000914 cFYI(1, "Error in RMFile = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915
916 cifs_buf_release(pSMB);
917 if (rc == -EAGAIN)
918 goto DelFileRetry;
919
920 return rc;
921}
922
923int
Steve French96daf2b2011-05-27 04:34:02 +0000924CIFSSMBRmDir(const int xid, struct cifs_tcon *tcon, const char *dirName,
Steve French737b7582005-04-28 22:41:06 -0700925 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926{
927 DELETE_DIRECTORY_REQ *pSMB = NULL;
928 DELETE_DIRECTORY_RSP *pSMBr = NULL;
929 int rc = 0;
930 int bytes_returned;
931 int name_len;
932
Joe Perchesb6b38f72010-04-21 03:50:45 +0000933 cFYI(1, "In CIFSSMBRmDir");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934RmDirRetry:
935 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
936 (void **) &pSMBr);
937 if (rc)
938 return rc;
939
940 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French737b7582005-04-28 22:41:06 -0700941 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
942 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943 name_len++; /* trailing null */
944 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700945 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946 name_len = strnlen(dirName, PATH_MAX);
947 name_len++; /* trailing null */
948 strncpy(pSMB->DirName, dirName, name_len);
949 }
950
951 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000952 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953 pSMB->ByteCount = cpu_to_le16(name_len + 1);
954 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
955 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700956 cifs_stats_inc(&tcon->num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000957 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000958 cFYI(1, "Error in RMDir = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959
960 cifs_buf_release(pSMB);
961 if (rc == -EAGAIN)
962 goto RmDirRetry;
963 return rc;
964}
965
966int
Steve French96daf2b2011-05-27 04:34:02 +0000967CIFSSMBMkDir(const int xid, struct cifs_tcon *tcon,
Steve French737b7582005-04-28 22:41:06 -0700968 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969{
970 int rc = 0;
971 CREATE_DIRECTORY_REQ *pSMB = NULL;
972 CREATE_DIRECTORY_RSP *pSMBr = NULL;
973 int bytes_returned;
974 int name_len;
975
Joe Perchesb6b38f72010-04-21 03:50:45 +0000976 cFYI(1, "In CIFSSMBMkDir");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977MkDirRetry:
978 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
979 (void **) &pSMBr);
980 if (rc)
981 return rc;
982
983 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +0000984 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
Steve French737b7582005-04-28 22:41:06 -0700985 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 name_len++; /* trailing null */
987 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700988 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989 name_len = strnlen(name, PATH_MAX);
990 name_len++; /* trailing null */
991 strncpy(pSMB->DirName, name, name_len);
992 }
993
994 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000995 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 pSMB->ByteCount = cpu_to_le16(name_len + 1);
997 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
998 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700999 cifs_stats_inc(&tcon->num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +00001000 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001001 cFYI(1, "Error in Mkdir = %d", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07001002
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 cifs_buf_release(pSMB);
1004 if (rc == -EAGAIN)
1005 goto MkDirRetry;
1006 return rc;
1007}
1008
Steve French2dd29d32007-04-23 22:07:35 +00001009int
Steve French96daf2b2011-05-27 04:34:02 +00001010CIFSPOSIXCreate(const int xid, struct cifs_tcon *tcon, __u32 posix_flags,
Steve Frenchad7a2922008-02-07 23:25:02 +00001011 __u64 mode, __u16 *netfid, FILE_UNIX_BASIC_INFO *pRetData,
Steve French50c2f752007-07-13 00:33:32 +00001012 __u32 *pOplock, const char *name,
Steve French2dd29d32007-04-23 22:07:35 +00001013 const struct nls_table *nls_codepage, int remap)
1014{
1015 TRANSACTION2_SPI_REQ *pSMB = NULL;
1016 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1017 int name_len;
1018 int rc = 0;
1019 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001020 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +00001021 OPEN_PSX_REQ *pdata;
1022 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +00001023
Joe Perchesb6b38f72010-04-21 03:50:45 +00001024 cFYI(1, "In POSIX Create");
Steve French2dd29d32007-04-23 22:07:35 +00001025PsxCreat:
1026 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1027 (void **) &pSMBr);
1028 if (rc)
1029 return rc;
1030
1031 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1032 name_len =
1033 cifsConvertToUCS((__le16 *) pSMB->FileName, name,
1034 PATH_MAX, nls_codepage, remap);
1035 name_len++; /* trailing null */
1036 name_len *= 2;
1037 } else { /* BB improve the check for buffer overruns BB */
1038 name_len = strnlen(name, PATH_MAX);
1039 name_len++; /* trailing null */
1040 strncpy(pSMB->FileName, name, name_len);
1041 }
1042
1043 params = 6 + name_len;
1044 count = sizeof(OPEN_PSX_REQ);
1045 pSMB->MaxParameterCount = cpu_to_le16(2);
1046 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1047 pSMB->MaxSetupCount = 0;
1048 pSMB->Reserved = 0;
1049 pSMB->Flags = 0;
1050 pSMB->Timeout = 0;
1051 pSMB->Reserved2 = 0;
1052 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001053 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001054 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001055 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001056 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001057 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001058 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001059 pdata->OpenFlags = cpu_to_le32(*pOplock);
1060 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1061 pSMB->DataOffset = cpu_to_le16(offset);
1062 pSMB->SetupCount = 1;
1063 pSMB->Reserved3 = 0;
1064 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1065 byte_count = 3 /* pad */ + params + count;
1066
1067 pSMB->DataCount = cpu_to_le16(count);
1068 pSMB->ParameterCount = cpu_to_le16(params);
1069 pSMB->TotalDataCount = pSMB->DataCount;
1070 pSMB->TotalParameterCount = pSMB->ParameterCount;
1071 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1072 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001073 inc_rfc1001_len(pSMB, byte_count);
Steve French2dd29d32007-04-23 22:07:35 +00001074 pSMB->ByteCount = cpu_to_le16(byte_count);
1075 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1076 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1077 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001078 cFYI(1, "Posix create returned %d", rc);
Steve French2dd29d32007-04-23 22:07:35 +00001079 goto psx_create_err;
1080 }
1081
Joe Perchesb6b38f72010-04-21 03:50:45 +00001082 cFYI(1, "copying inode info");
Steve French2dd29d32007-04-23 22:07:35 +00001083 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1084
Jeff Layton820a8032011-05-04 08:05:26 -04001085 if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) {
Steve French2dd29d32007-04-23 22:07:35 +00001086 rc = -EIO; /* bad smb */
1087 goto psx_create_err;
1088 }
1089
1090 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001091 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001092 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001093
Steve French2dd29d32007-04-23 22:07:35 +00001094 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001095 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001096 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1097 /* Let caller know file was created so we can set the mode. */
1098 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001099 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001100 *pOplock |= CIFS_CREATE_ACTION;
1101 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001102 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1103 pRetData->Type = cpu_to_le32(-1); /* unknown */
Joe Perchesb6b38f72010-04-21 03:50:45 +00001104 cFYI(DBG2, "unknown type");
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001105 } else {
Jeff Layton820a8032011-05-04 08:05:26 -04001106 if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001107 + sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001108 cERROR(1, "Open response data too small");
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001109 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001110 goto psx_create_err;
1111 }
Steve French50c2f752007-07-13 00:33:32 +00001112 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001113 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001114 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001115 }
Steve French2dd29d32007-04-23 22:07:35 +00001116
1117psx_create_err:
1118 cifs_buf_release(pSMB);
1119
Steve French65bc98b2009-07-10 15:27:25 +00001120 if (posix_flags & SMB_O_DIRECTORY)
1121 cifs_stats_inc(&tcon->num_posixmkdirs);
1122 else
1123 cifs_stats_inc(&tcon->num_posixopens);
Steve French2dd29d32007-04-23 22:07:35 +00001124
1125 if (rc == -EAGAIN)
1126 goto PsxCreat;
1127
Steve French50c2f752007-07-13 00:33:32 +00001128 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001129}
1130
Steve Frencha9d02ad2005-08-24 23:06:05 -07001131static __u16 convert_disposition(int disposition)
1132{
1133 __u16 ofun = 0;
1134
1135 switch (disposition) {
1136 case FILE_SUPERSEDE:
1137 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1138 break;
1139 case FILE_OPEN:
1140 ofun = SMBOPEN_OAPPEND;
1141 break;
1142 case FILE_CREATE:
1143 ofun = SMBOPEN_OCREATE;
1144 break;
1145 case FILE_OPEN_IF:
1146 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1147 break;
1148 case FILE_OVERWRITE:
1149 ofun = SMBOPEN_OTRUNC;
1150 break;
1151 case FILE_OVERWRITE_IF:
1152 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1153 break;
1154 default:
Joe Perchesb6b38f72010-04-21 03:50:45 +00001155 cFYI(1, "unknown disposition %d", disposition);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001156 ofun = SMBOPEN_OAPPEND; /* regular open */
1157 }
1158 return ofun;
1159}
1160
Jeff Layton35fc37d2008-05-14 10:22:03 -07001161static int
1162access_flags_to_smbopen_mode(const int access_flags)
1163{
1164 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1165
1166 if (masked_flags == GENERIC_READ)
1167 return SMBOPEN_READ;
1168 else if (masked_flags == GENERIC_WRITE)
1169 return SMBOPEN_WRITE;
1170
1171 /* just go for read/write */
1172 return SMBOPEN_READWRITE;
1173}
1174
Steve Frencha9d02ad2005-08-24 23:06:05 -07001175int
Steve French96daf2b2011-05-27 04:34:02 +00001176SMBLegacyOpen(const int xid, struct cifs_tcon *tcon,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001177 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001178 const int access_flags, const int create_options, __u16 *netfid,
1179 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001180 const struct nls_table *nls_codepage, int remap)
1181{
1182 int rc = -EACCES;
1183 OPENX_REQ *pSMB = NULL;
1184 OPENX_RSP *pSMBr = NULL;
1185 int bytes_returned;
1186 int name_len;
1187 __u16 count;
1188
1189OldOpenRetry:
1190 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1191 (void **) &pSMBr);
1192 if (rc)
1193 return rc;
1194
1195 pSMB->AndXCommand = 0xFF; /* none */
1196
1197 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1198 count = 1; /* account for one byte pad to word boundary */
1199 name_len =
1200 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1201 fileName, PATH_MAX, nls_codepage, remap);
1202 name_len++; /* trailing null */
1203 name_len *= 2;
1204 } else { /* BB improve check for buffer overruns BB */
1205 count = 0; /* no pad */
1206 name_len = strnlen(fileName, PATH_MAX);
1207 name_len++; /* trailing null */
1208 strncpy(pSMB->fileName, fileName, name_len);
1209 }
1210 if (*pOplock & REQ_OPLOCK)
1211 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001212 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001213 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001214
Steve Frencha9d02ad2005-08-24 23:06:05 -07001215 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001216 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001217 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1218 /* set file as system file if special file such
1219 as fifo and server expecting SFU style and
1220 no Unix extensions */
1221
Steve French790fe572007-07-07 19:25:05 +00001222 if (create_options & CREATE_OPTION_SPECIAL)
1223 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001224 else /* BB FIXME BB */
1225 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001226
Jeff Layton67750fb2008-05-09 22:28:02 +00001227 if (create_options & CREATE_OPTION_READONLY)
1228 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001229
1230 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001231/* pSMB->CreateOptions = cpu_to_le32(create_options &
1232 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001233 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001234
1235 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001236 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001237 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001238 inc_rfc1001_len(pSMB, count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001239
1240 pSMB->ByteCount = cpu_to_le16(count);
1241 /* long_op set to 1 to allow for oplock break timeouts */
1242 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001243 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001244 cifs_stats_inc(&tcon->num_opens);
1245 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001246 cFYI(1, "Error in Open = %d", rc);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001247 } else {
1248 /* BB verify if wct == 15 */
1249
Steve French582d21e2008-05-13 04:54:12 +00001250/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001251
1252 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1253 /* Let caller know file was created so we can set the mode. */
1254 /* Do we care about the CreateAction in any other cases? */
1255 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001256/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001257 *pOplock |= CIFS_CREATE_ACTION; */
1258 /* BB FIXME END */
1259
Steve French790fe572007-07-07 19:25:05 +00001260 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001261 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1262 pfile_info->LastAccessTime = 0; /* BB fixme */
1263 pfile_info->LastWriteTime = 0; /* BB fixme */
1264 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001265 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001266 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001267 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001268 pfile_info->AllocationSize =
1269 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1270 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001271 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001272 pfile_info->DeletePending = 0;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001273 }
1274 }
1275
1276 cifs_buf_release(pSMB);
1277 if (rc == -EAGAIN)
1278 goto OldOpenRetry;
1279 return rc;
1280}
1281
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282int
Steve French96daf2b2011-05-27 04:34:02 +00001283CIFSSMBOpen(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001285 const int access_flags, const int create_options, __u16 *netfid,
1286 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001287 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288{
1289 int rc = -EACCES;
1290 OPEN_REQ *pSMB = NULL;
1291 OPEN_RSP *pSMBr = NULL;
1292 int bytes_returned;
1293 int name_len;
1294 __u16 count;
1295
1296openRetry:
1297 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1298 (void **) &pSMBr);
1299 if (rc)
1300 return rc;
1301
1302 pSMB->AndXCommand = 0xFF; /* none */
1303
1304 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1305 count = 1; /* account for one byte pad to word boundary */
1306 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001307 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -07001308 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001309 name_len++; /* trailing null */
1310 name_len *= 2;
1311 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001312 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313 count = 0; /* no pad */
1314 name_len = strnlen(fileName, PATH_MAX);
1315 name_len++; /* trailing null */
1316 pSMB->NameLength = cpu_to_le16(name_len);
1317 strncpy(pSMB->fileName, fileName, name_len);
1318 }
1319 if (*pOplock & REQ_OPLOCK)
1320 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001321 else if (*pOplock & REQ_BATCHOPLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1324 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -07001325 /* set file as system file if special file such
1326 as fifo and server expecting SFU style and
1327 no Unix extensions */
Steve French790fe572007-07-07 19:25:05 +00001328 if (create_options & CREATE_OPTION_SPECIAL)
Steve Frencheda3c0292005-07-21 15:20:28 -07001329 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1330 else
1331 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Jeff Layton67750fb2008-05-09 22:28:02 +00001332
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333 /* XP does not handle ATTR_POSIX_SEMANTICS */
1334 /* but it helps speed up case sensitive checks for other
1335 servers such as Samba */
1336 if (tcon->ses->capabilities & CAP_UNIX)
1337 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1338
Jeff Layton67750fb2008-05-09 22:28:02 +00001339 if (create_options & CREATE_OPTION_READONLY)
1340 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1341
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1343 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -07001344 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001345 /* BB Expirement with various impersonation levels and verify */
1346 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347 pSMB->SecurityFlags =
1348 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1349
1350 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001351 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352
1353 pSMB->ByteCount = cpu_to_le16(count);
1354 /* long_op set to 1 to allow for oplock break timeouts */
1355 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001356 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001357 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001359 cFYI(1, "Error in Open = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360 } else {
Steve French09d1db52005-04-28 22:41:08 -07001361 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1363 /* Let caller know file was created so we can set the mode. */
1364 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001365 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve French50c2f752007-07-13 00:33:32 +00001366 *pOplock |= CIFS_CREATE_ACTION;
Steve French790fe572007-07-07 19:25:05 +00001367 if (pfile_info) {
Steve French61e74802008-12-03 00:57:54 +00001368 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1369 36 /* CreationTime to Attributes */);
1370 /* the file_info buf is endian converted by caller */
1371 pfile_info->AllocationSize = pSMBr->AllocationSize;
1372 pfile_info->EndOfFile = pSMBr->EndOfFile;
1373 pfile_info->NumberOfLinks = cpu_to_le32(1);
1374 pfile_info->DeletePending = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001377
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378 cifs_buf_release(pSMB);
1379 if (rc == -EAGAIN)
1380 goto openRetry;
1381 return rc;
1382}
1383
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001384struct cifs_readdata *
1385cifs_readdata_alloc(unsigned int nr_pages)
1386{
1387 struct cifs_readdata *rdata;
1388
1389 /* readdata + 1 kvec for each page */
1390 rdata = kzalloc(sizeof(*rdata) +
1391 sizeof(struct kvec) * nr_pages, GFP_KERNEL);
1392 if (rdata != NULL) {
1393 INIT_WORK(&rdata->work, cifs_readv_complete);
1394 INIT_LIST_HEAD(&rdata->pages);
1395 }
1396 return rdata;
1397}
1398
1399void
1400cifs_readdata_free(struct cifs_readdata *rdata)
1401{
1402 cifsFileInfo_put(rdata->cfile);
1403 kfree(rdata);
1404}
1405
1406/*
1407 * Discard any remaining data in the current SMB. To do this, we borrow the
1408 * current bigbuf.
1409 */
1410static int
1411cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1412{
1413 READ_RSP *rsp = (READ_RSP *)server->smallbuf;
1414 unsigned int rfclen = be32_to_cpu(rsp->hdr.smb_buf_length);
1415 int remaining = rfclen + 4 - server->total_read;
1416 struct cifs_readdata *rdata = mid->callback_data;
1417
1418 while (remaining > 0) {
1419 int length;
1420
1421 length = cifs_read_from_socket(server, server->bigbuf,
1422 min_t(unsigned int, remaining,
1423 CIFSMaxBufSize + MAX_CIFS_HDR_SIZE));
1424 if (length < 0)
1425 return length;
1426 server->total_read += length;
1427 remaining -= length;
1428 }
1429
1430 dequeue_mid(mid, rdata->result);
1431 return 0;
1432}
1433
1434static int
1435cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1436{
1437 int length, len;
1438 unsigned int data_offset, remaining, data_len;
1439 struct cifs_readdata *rdata = mid->callback_data;
1440 READ_RSP *rsp = (READ_RSP *)server->smallbuf;
1441 unsigned int rfclen = be32_to_cpu(rsp->hdr.smb_buf_length) + 4;
1442 u64 eof;
1443 pgoff_t eof_index;
1444 struct page *page, *tpage;
1445
1446 cFYI(1, "%s: mid=%u offset=%llu bytes=%u", __func__,
1447 mid->mid, rdata->offset, rdata->bytes);
1448
1449 /*
1450 * read the rest of READ_RSP header (sans Data array), or whatever we
1451 * can if there's not enough data. At this point, we've read down to
1452 * the Mid.
1453 */
1454 len = min_t(unsigned int, rfclen, sizeof(*rsp)) -
1455 sizeof(struct smb_hdr) + 1;
1456
1457 rdata->iov[0].iov_base = server->smallbuf + sizeof(struct smb_hdr) - 1;
1458 rdata->iov[0].iov_len = len;
1459
1460 length = cifs_readv_from_socket(server, rdata->iov, 1, len);
1461 if (length < 0)
1462 return length;
1463 server->total_read += length;
1464
1465 /* Was the SMB read successful? */
1466 rdata->result = map_smb_to_linux_error(&rsp->hdr, false);
1467 if (rdata->result != 0) {
1468 cFYI(1, "%s: server returned error %d", __func__,
1469 rdata->result);
1470 return cifs_readv_discard(server, mid);
1471 }
1472
1473 /* Is there enough to get to the rest of the READ_RSP header? */
1474 if (server->total_read < sizeof(READ_RSP)) {
1475 cFYI(1, "%s: server returned short header. got=%u expected=%zu",
1476 __func__, server->total_read, sizeof(READ_RSP));
1477 rdata->result = -EIO;
1478 return cifs_readv_discard(server, mid);
1479 }
1480
1481 data_offset = le16_to_cpu(rsp->DataOffset) + 4;
1482 if (data_offset < server->total_read) {
1483 /*
1484 * win2k8 sometimes sends an offset of 0 when the read
1485 * is beyond the EOF. Treat it as if the data starts just after
1486 * the header.
1487 */
1488 cFYI(1, "%s: data offset (%u) inside read response header",
1489 __func__, data_offset);
1490 data_offset = server->total_read;
1491 } else if (data_offset > MAX_CIFS_SMALL_BUFFER_SIZE) {
1492 /* data_offset is beyond the end of smallbuf */
1493 cFYI(1, "%s: data offset (%u) beyond end of smallbuf",
1494 __func__, data_offset);
1495 rdata->result = -EIO;
1496 return cifs_readv_discard(server, mid);
1497 }
1498
1499 cFYI(1, "%s: total_read=%u data_offset=%u", __func__,
1500 server->total_read, data_offset);
1501
1502 len = data_offset - server->total_read;
1503 if (len > 0) {
1504 /* read any junk before data into the rest of smallbuf */
1505 rdata->iov[0].iov_base = server->smallbuf + server->total_read;
1506 rdata->iov[0].iov_len = len;
1507 length = cifs_readv_from_socket(server, rdata->iov, 1, len);
1508 if (length < 0)
1509 return length;
1510 server->total_read += length;
1511 }
1512
1513 /* set up first iov for signature check */
1514 rdata->iov[0].iov_base = server->smallbuf;
1515 rdata->iov[0].iov_len = server->total_read;
1516 cFYI(1, "0: iov_base=%p iov_len=%zu",
1517 rdata->iov[0].iov_base, rdata->iov[0].iov_len);
1518
1519 /* how much data is in the response? */
1520 data_len = le16_to_cpu(rsp->DataLengthHigh) << 16;
1521 data_len += le16_to_cpu(rsp->DataLength);
1522 if (data_offset + data_len > rfclen) {
1523 /* data_len is corrupt -- discard frame */
1524 rdata->result = -EIO;
1525 return cifs_readv_discard(server, mid);
1526 }
1527
1528 /* marshal up the page array */
1529 len = 0;
1530 remaining = data_len;
1531 rdata->nr_iov = 1;
1532
1533 /* determine the eof that the server (probably) has */
1534 eof = CIFS_I(rdata->mapping->host)->server_eof;
1535 eof_index = eof ? (eof - 1) >> PAGE_CACHE_SHIFT : 0;
1536 cFYI(1, "eof=%llu eof_index=%lu", eof, eof_index);
1537
1538 list_for_each_entry_safe(page, tpage, &rdata->pages, lru) {
1539 if (remaining >= PAGE_CACHE_SIZE) {
1540 /* enough data to fill the page */
1541 rdata->iov[rdata->nr_iov].iov_base = kmap(page);
1542 rdata->iov[rdata->nr_iov].iov_len = PAGE_CACHE_SIZE;
1543 cFYI(1, "%u: idx=%lu iov_base=%p iov_len=%zu",
1544 rdata->nr_iov, page->index,
1545 rdata->iov[rdata->nr_iov].iov_base,
1546 rdata->iov[rdata->nr_iov].iov_len);
1547 ++rdata->nr_iov;
1548 len += PAGE_CACHE_SIZE;
1549 remaining -= PAGE_CACHE_SIZE;
1550 } else if (remaining > 0) {
1551 /* enough for partial page, fill and zero the rest */
1552 rdata->iov[rdata->nr_iov].iov_base = kmap(page);
1553 rdata->iov[rdata->nr_iov].iov_len = remaining;
1554 cFYI(1, "%u: idx=%lu iov_base=%p iov_len=%zu",
1555 rdata->nr_iov, page->index,
1556 rdata->iov[rdata->nr_iov].iov_base,
1557 rdata->iov[rdata->nr_iov].iov_len);
1558 memset(rdata->iov[rdata->nr_iov].iov_base + remaining,
1559 '\0', PAGE_CACHE_SIZE - remaining);
1560 ++rdata->nr_iov;
1561 len += remaining;
1562 remaining = 0;
1563 } else if (page->index > eof_index) {
1564 /*
1565 * The VFS will not try to do readahead past the
1566 * i_size, but it's possible that we have outstanding
1567 * writes with gaps in the middle and the i_size hasn't
1568 * caught up yet. Populate those with zeroed out pages
1569 * to prevent the VFS from repeatedly attempting to
1570 * fill them until the writes are flushed.
1571 */
1572 zero_user(page, 0, PAGE_CACHE_SIZE);
1573 list_del(&page->lru);
1574 lru_cache_add_file(page);
1575 flush_dcache_page(page);
1576 SetPageUptodate(page);
1577 unlock_page(page);
1578 page_cache_release(page);
1579 } else {
1580 /* no need to hold page hostage */
1581 list_del(&page->lru);
1582 lru_cache_add_file(page);
1583 unlock_page(page);
1584 page_cache_release(page);
1585 }
1586 }
1587
1588 /* issue the read if we have any iovecs left to fill */
1589 if (rdata->nr_iov > 1) {
1590 length = cifs_readv_from_socket(server, &rdata->iov[1],
1591 rdata->nr_iov - 1, len);
1592 if (length < 0)
1593 return length;
1594 server->total_read += length;
1595 } else {
1596 length = 0;
1597 }
1598
1599 rdata->bytes = length;
1600
1601 cFYI(1, "total_read=%u rfclen=%u remaining=%u", server->total_read,
1602 rfclen, remaining);
1603
1604 /* discard anything left over */
1605 if (server->total_read < rfclen)
1606 return cifs_readv_discard(server, mid);
1607
1608 dequeue_mid(mid, false);
1609 return length;
1610}
1611
1612static void
1613cifs_readv_complete(struct work_struct *work)
1614{
1615 struct cifs_readdata *rdata = container_of(work,
1616 struct cifs_readdata, work);
1617 struct page *page, *tpage;
1618
1619 list_for_each_entry_safe(page, tpage, &rdata->pages, lru) {
1620 list_del(&page->lru);
1621 lru_cache_add_file(page);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001622
1623 if (rdata->result == 0) {
Pavel Shilovskya2d6b6c2011-10-21 10:14:04 +04001624 kunmap(page);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001625 flush_dcache_page(page);
1626 SetPageUptodate(page);
1627 }
1628
1629 unlock_page(page);
1630
1631 if (rdata->result == 0)
1632 cifs_readpage_to_fscache(rdata->mapping->host, page);
1633
1634 page_cache_release(page);
1635 }
1636 cifs_readdata_free(rdata);
1637}
1638
1639static void
1640cifs_readv_callback(struct mid_q_entry *mid)
1641{
1642 struct cifs_readdata *rdata = mid->callback_data;
1643 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1644 struct TCP_Server_Info *server = tcon->ses->server;
1645
1646 cFYI(1, "%s: mid=%u state=%d result=%d bytes=%u", __func__,
1647 mid->mid, mid->midState, rdata->result, rdata->bytes);
1648
1649 switch (mid->midState) {
1650 case MID_RESPONSE_RECEIVED:
1651 /* result already set, check signature */
1652 if (server->sec_mode &
1653 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
1654 if (cifs_verify_signature(rdata->iov, rdata->nr_iov,
1655 server, mid->sequence_number + 1))
1656 cERROR(1, "Unexpected SMB signature");
1657 }
1658 /* FIXME: should this be counted toward the initiating task? */
1659 task_io_account_read(rdata->bytes);
1660 cifs_stats_bytes_read(tcon, rdata->bytes);
1661 break;
1662 case MID_REQUEST_SUBMITTED:
1663 case MID_RETRY_NEEDED:
1664 rdata->result = -EAGAIN;
1665 break;
1666 default:
1667 rdata->result = -EIO;
1668 }
1669
1670 queue_work(system_nrt_wq, &rdata->work);
1671 DeleteMidQEntry(mid);
1672 atomic_dec(&server->inFlight);
1673 wake_up(&server->request_q);
1674}
1675
1676/* cifs_async_readv - send an async write, and set up mid to handle result */
1677int
1678cifs_async_readv(struct cifs_readdata *rdata)
1679{
1680 int rc;
1681 READ_REQ *smb = NULL;
1682 int wct;
1683 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1684
1685 cFYI(1, "%s: offset=%llu bytes=%u", __func__,
1686 rdata->offset, rdata->bytes);
1687
1688 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1689 wct = 12;
1690 else {
1691 wct = 10; /* old style read */
1692 if ((rdata->offset >> 32) > 0) {
1693 /* can not handle this big offset for old */
1694 return -EIO;
1695 }
1696 }
1697
1698 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **)&smb);
1699 if (rc)
1700 return rc;
1701
1702 smb->hdr.Pid = cpu_to_le16((__u16)rdata->pid);
1703 smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16));
1704
1705 smb->AndXCommand = 0xFF; /* none */
1706 smb->Fid = rdata->cfile->netfid;
1707 smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF);
1708 if (wct == 12)
1709 smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32);
1710 smb->Remaining = 0;
1711 smb->MaxCount = cpu_to_le16(rdata->bytes & 0xFFFF);
1712 smb->MaxCountHigh = cpu_to_le32(rdata->bytes >> 16);
1713 if (wct == 12)
1714 smb->ByteCount = 0;
1715 else {
1716 /* old style read */
1717 struct smb_com_readx_req *smbr =
1718 (struct smb_com_readx_req *)smb;
1719 smbr->ByteCount = 0;
1720 }
1721
1722 /* 4 for RFC1001 length + 1 for BCC */
1723 rdata->iov[0].iov_base = smb;
1724 rdata->iov[0].iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
1725
1726 rc = cifs_call_async(tcon->ses->server, rdata->iov, 1,
1727 cifs_readv_receive, cifs_readv_callback,
1728 rdata, false);
1729
1730 if (rc == 0)
1731 cifs_stats_inc(&tcon->num_reads);
1732
1733 cifs_small_buf_release(smb);
1734 return rc;
1735}
1736
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737int
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001738CIFSSMBRead(const int xid, struct cifs_io_parms *io_parms, unsigned int *nbytes,
Steve French50c2f752007-07-13 00:33:32 +00001739 char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740{
1741 int rc = -EACCES;
1742 READ_REQ *pSMB = NULL;
1743 READ_RSP *pSMBr = NULL;
1744 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001745 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001746 int resp_buf_type = 0;
1747 struct kvec iov[1];
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001748 __u32 pid = io_parms->pid;
1749 __u16 netfid = io_parms->netfid;
1750 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001751 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001752 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753
Joe Perchesb6b38f72010-04-21 03:50:45 +00001754 cFYI(1, "Reading %d bytes on fid %d", count, netfid);
Steve French790fe572007-07-07 19:25:05 +00001755 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001756 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001757 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001758 wct = 10; /* old style read */
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001759 if ((offset >> 32) > 0) {
Steve French4c3130e2008-12-09 00:28:16 +00001760 /* can not handle this big offset for old */
1761 return -EIO;
1762 }
1763 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001764
1765 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001766 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767 if (rc)
1768 return rc;
1769
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001770 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1771 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1772
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773 /* tcon and ses pointer are checked in smb_init */
1774 if (tcon->ses->server == NULL)
1775 return -ECONNABORTED;
1776
Steve Frenchec637e32005-12-12 20:53:18 -08001777 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778 pSMB->Fid = netfid;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001779 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001780 if (wct == 12)
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001781 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001782
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783 pSMB->Remaining = 0;
1784 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1785 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001786 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001787 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1788 else {
1789 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001790 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001791 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001792 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001793 }
Steve Frenchec637e32005-12-12 20:53:18 -08001794
1795 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001796 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve Frencha761ac52007-10-18 21:45:27 +00001797 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Jeff Layton77499812011-01-11 07:24:23 -05001798 &resp_buf_type, CIFS_LOG_ERROR);
Steve Frencha4544342005-08-24 13:59:35 -07001799 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001800 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001802 cERROR(1, "Send error in read = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803 } else {
1804 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1805 data_length = data_length << 16;
1806 data_length += le16_to_cpu(pSMBr->DataLength);
1807 *nbytes = data_length;
1808
1809 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001810 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811 || (data_length > count)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001812 cFYI(1, "bad length %d for count %d",
1813 data_length, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001814 rc = -EIO;
1815 *nbytes = 0;
1816 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001817 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001818 le16_to_cpu(pSMBr->DataOffset);
1819/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001820 cERROR(1, "Faulting on read rc = %d",rc);
Steve French50c2f752007-07-13 00:33:32 +00001821 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001822 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001823 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001824 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001825 }
1826 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001827
Steve French4b8f9302006-02-26 16:41:18 +00001828/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001829 if (*buf) {
1830 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001831 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001832 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001833 cifs_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001834 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001835 /* return buffer to caller to free */
1836 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001837 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001838 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001839 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001840 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001841 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001842
1843 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844 since file handle passed in no longer valid */
1845 return rc;
1846}
1847
Steve Frenchec637e32005-12-12 20:53:18 -08001848
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849int
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001850CIFSSMBWrite(const int xid, struct cifs_io_parms *io_parms,
1851 unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001852 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853{
1854 int rc = -EACCES;
1855 WRITE_REQ *pSMB = NULL;
1856 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001857 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858 __u32 bytes_sent;
1859 __u16 byte_count;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001860 __u32 pid = io_parms->pid;
1861 __u16 netfid = io_parms->netfid;
1862 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001863 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001864 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865
Steve Frencha24e2d72010-04-03 17:20:21 +00001866 *nbytes = 0;
1867
Joe Perchesb6b38f72010-04-21 03:50:45 +00001868 /* cFYI(1, "write at %lld %d bytes", offset, count);*/
Steve French790fe572007-07-07 19:25:05 +00001869 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001870 return -ECONNABORTED;
1871
Steve French790fe572007-07-07 19:25:05 +00001872 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001873 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001874 else {
Steve French1c955182005-08-30 20:58:07 -07001875 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001876 if ((offset >> 32) > 0) {
1877 /* can not handle big offset for old srv */
1878 return -EIO;
1879 }
1880 }
Steve French1c955182005-08-30 20:58:07 -07001881
1882 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001883 (void **) &pSMBr);
1884 if (rc)
1885 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001886
1887 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1888 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1889
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890 /* tcon and ses pointer are checked in smb_init */
1891 if (tcon->ses->server == NULL)
1892 return -ECONNABORTED;
1893
1894 pSMB->AndXCommand = 0xFF; /* none */
1895 pSMB->Fid = netfid;
1896 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001897 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001898 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001899
Linus Torvalds1da177e2005-04-16 15:20:36 -07001900 pSMB->Reserved = 0xFFFFFFFF;
1901 pSMB->WriteMode = 0;
1902 pSMB->Remaining = 0;
1903
Steve French50c2f752007-07-13 00:33:32 +00001904 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905 can send more if LARGE_WRITE_X capability returned by the server and if
1906 our buffer is big enough or if we convert to iovecs on socket writes
1907 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001908 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1910 } else {
1911 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1912 & ~0xFF;
1913 }
1914
1915 if (bytes_sent > count)
1916 bytes_sent = count;
1917 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001918 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001919 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001920 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001921 else if (ubuf) {
1922 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923 cifs_buf_release(pSMB);
1924 return -EFAULT;
1925 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001926 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001927 /* No buffer */
1928 cifs_buf_release(pSMB);
1929 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001930 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001931 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001932 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001933 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001934 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001935
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1937 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001938 inc_rfc1001_len(pSMB, byte_count);
Steve French1c955182005-08-30 20:58:07 -07001939
Steve French790fe572007-07-07 19:25:05 +00001940 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001941 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001942 else { /* old style write has byte count 4 bytes earlier
1943 so 4 bytes pad */
1944 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001945 (struct smb_com_writex_req *)pSMB;
1946 pSMBW->ByteCount = cpu_to_le16(byte_count);
1947 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948
1949 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1950 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001951 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00001953 cFYI(1, "Send error in write = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001954 } else {
1955 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1956 *nbytes = (*nbytes) << 16;
1957 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301958
1959 /*
1960 * Mask off high 16 bits when bytes written as returned by the
1961 * server is greater than bytes requested by the client. Some
1962 * OS/2 servers are known to set incorrect CountHigh values.
1963 */
1964 if (*nbytes > count)
1965 *nbytes &= 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001966 }
1967
1968 cifs_buf_release(pSMB);
1969
Steve French50c2f752007-07-13 00:33:32 +00001970 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001971 since file handle passed in no longer valid */
1972
1973 return rc;
1974}
1975
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001976void
1977cifs_writedata_release(struct kref *refcount)
1978{
1979 struct cifs_writedata *wdata = container_of(refcount,
1980 struct cifs_writedata, refcount);
1981
1982 if (wdata->cfile)
1983 cifsFileInfo_put(wdata->cfile);
1984
1985 kfree(wdata);
1986}
1987
1988/*
1989 * Write failed with a retryable error. Resend the write request. It's also
1990 * possible that the page was redirtied so re-clean the page.
1991 */
1992static void
1993cifs_writev_requeue(struct cifs_writedata *wdata)
1994{
1995 int i, rc;
1996 struct inode *inode = wdata->cfile->dentry->d_inode;
1997
1998 for (i = 0; i < wdata->nr_pages; i++) {
1999 lock_page(wdata->pages[i]);
2000 clear_page_dirty_for_io(wdata->pages[i]);
2001 }
2002
2003 do {
2004 rc = cifs_async_writev(wdata);
2005 } while (rc == -EAGAIN);
2006
2007 for (i = 0; i < wdata->nr_pages; i++) {
2008 if (rc != 0)
2009 SetPageError(wdata->pages[i]);
2010 unlock_page(wdata->pages[i]);
2011 }
2012
2013 mapping_set_error(inode->i_mapping, rc);
2014 kref_put(&wdata->refcount, cifs_writedata_release);
2015}
2016
2017static void
2018cifs_writev_complete(struct work_struct *work)
2019{
2020 struct cifs_writedata *wdata = container_of(work,
2021 struct cifs_writedata, work);
2022 struct inode *inode = wdata->cfile->dentry->d_inode;
2023 int i = 0;
2024
2025 if (wdata->result == 0) {
2026 cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
2027 cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
2028 wdata->bytes);
2029 } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
2030 return cifs_writev_requeue(wdata);
2031
2032 for (i = 0; i < wdata->nr_pages; i++) {
2033 struct page *page = wdata->pages[i];
2034 if (wdata->result == -EAGAIN)
2035 __set_page_dirty_nobuffers(page);
2036 else if (wdata->result < 0)
2037 SetPageError(page);
2038 end_page_writeback(page);
2039 page_cache_release(page);
2040 }
2041 if (wdata->result != -EAGAIN)
2042 mapping_set_error(inode->i_mapping, wdata->result);
2043 kref_put(&wdata->refcount, cifs_writedata_release);
2044}
2045
2046struct cifs_writedata *
2047cifs_writedata_alloc(unsigned int nr_pages)
2048{
2049 struct cifs_writedata *wdata;
2050
2051 /* this would overflow */
2052 if (nr_pages == 0) {
2053 cERROR(1, "%s: called with nr_pages == 0!", __func__);
2054 return NULL;
2055 }
2056
2057 /* writedata + number of page pointers */
2058 wdata = kzalloc(sizeof(*wdata) +
2059 sizeof(struct page *) * (nr_pages - 1), GFP_NOFS);
2060 if (wdata != NULL) {
2061 INIT_WORK(&wdata->work, cifs_writev_complete);
2062 kref_init(&wdata->refcount);
2063 }
2064 return wdata;
2065}
2066
2067/*
2068 * Check the midState and signature on received buffer (if any), and queue the
2069 * workqueue completion task.
2070 */
2071static void
2072cifs_writev_callback(struct mid_q_entry *mid)
2073{
2074 struct cifs_writedata *wdata = mid->callback_data;
Steve French96daf2b2011-05-27 04:34:02 +00002075 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002076 unsigned int written;
2077 WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
2078
2079 switch (mid->midState) {
2080 case MID_RESPONSE_RECEIVED:
2081 wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
2082 if (wdata->result != 0)
2083 break;
2084
2085 written = le16_to_cpu(smb->CountHigh);
2086 written <<= 16;
2087 written += le16_to_cpu(smb->Count);
2088 /*
2089 * Mask off high 16 bits when bytes written as returned
2090 * by the server is greater than bytes requested by the
2091 * client. OS/2 servers are known to set incorrect
2092 * CountHigh values.
2093 */
2094 if (written > wdata->bytes)
2095 written &= 0xFFFF;
2096
2097 if (written < wdata->bytes)
2098 wdata->result = -ENOSPC;
2099 else
2100 wdata->bytes = written;
2101 break;
2102 case MID_REQUEST_SUBMITTED:
2103 case MID_RETRY_NEEDED:
2104 wdata->result = -EAGAIN;
2105 break;
2106 default:
2107 wdata->result = -EIO;
2108 break;
2109 }
2110
2111 queue_work(system_nrt_wq, &wdata->work);
2112 DeleteMidQEntry(mid);
2113 atomic_dec(&tcon->ses->server->inFlight);
2114 wake_up(&tcon->ses->server->request_q);
2115}
2116
2117/* cifs_async_writev - send an async write, and set up mid to handle result */
2118int
2119cifs_async_writev(struct cifs_writedata *wdata)
2120{
2121 int i, rc = -EACCES;
2122 WRITE_REQ *smb = NULL;
2123 int wct;
Steve French96daf2b2011-05-27 04:34:02 +00002124 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002125 struct inode *inode = wdata->cfile->dentry->d_inode;
2126 struct kvec *iov = NULL;
2127
2128 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
2129 wct = 14;
2130 } else {
2131 wct = 12;
2132 if (wdata->offset >> 32 > 0) {
2133 /* can not handle big offset for old srv */
2134 return -EIO;
2135 }
2136 }
2137
2138 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
2139 if (rc)
2140 goto async_writev_out;
2141
2142 /* 1 iov per page + 1 for header */
2143 iov = kzalloc((wdata->nr_pages + 1) * sizeof(*iov), GFP_NOFS);
2144 if (iov == NULL) {
2145 rc = -ENOMEM;
2146 goto async_writev_out;
2147 }
2148
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002149 smb->hdr.Pid = cpu_to_le16((__u16)wdata->cfile->pid);
2150 smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->cfile->pid >> 16));
2151
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002152 smb->AndXCommand = 0xFF; /* none */
2153 smb->Fid = wdata->cfile->netfid;
2154 smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
2155 if (wct == 14)
2156 smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
2157 smb->Reserved = 0xFFFFFFFF;
2158 smb->WriteMode = 0;
2159 smb->Remaining = 0;
2160
2161 smb->DataOffset =
2162 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
2163
2164 /* 4 for RFC1001 length + 1 for BCC */
2165 iov[0].iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4 + 1;
2166 iov[0].iov_base = smb;
2167
2168 /* marshal up the pages into iov array */
2169 wdata->bytes = 0;
2170 for (i = 0; i < wdata->nr_pages; i++) {
2171 iov[i + 1].iov_len = min(inode->i_size -
2172 page_offset(wdata->pages[i]),
2173 (loff_t)PAGE_CACHE_SIZE);
2174 iov[i + 1].iov_base = kmap(wdata->pages[i]);
2175 wdata->bytes += iov[i + 1].iov_len;
2176 }
2177
2178 cFYI(1, "async write at %llu %u bytes", wdata->offset, wdata->bytes);
2179
2180 smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
2181 smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16);
2182
2183 if (wct == 14) {
2184 inc_rfc1001_len(&smb->hdr, wdata->bytes + 1);
2185 put_bcc(wdata->bytes + 1, &smb->hdr);
2186 } else {
2187 /* wct == 12 */
2188 struct smb_com_writex_req *smbw =
2189 (struct smb_com_writex_req *)smb;
2190 inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
2191 put_bcc(wdata->bytes + 5, &smbw->hdr);
2192 iov[0].iov_len += 4; /* pad bigger by four bytes */
2193 }
2194
2195 kref_get(&wdata->refcount);
2196 rc = cifs_call_async(tcon->ses->server, iov, wdata->nr_pages + 1,
Jeff Layton44d22d82011-10-19 15:29:49 -04002197 NULL, cifs_writev_callback, wdata, false);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002198
2199 if (rc == 0)
2200 cifs_stats_inc(&tcon->num_writes);
2201 else
2202 kref_put(&wdata->refcount, cifs_writedata_release);
2203
2204 /* send is done, unmap pages */
2205 for (i = 0; i < wdata->nr_pages; i++)
2206 kunmap(wdata->pages[i]);
2207
2208async_writev_out:
2209 cifs_small_buf_release(smb);
2210 kfree(iov);
2211 return rc;
2212}
2213
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002214int
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002215CIFSSMBWrite2(const int xid, struct cifs_io_parms *io_parms,
2216 unsigned int *nbytes, struct kvec *iov, int n_vec,
2217 const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002218{
2219 int rc = -EACCES;
2220 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08002221 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002222 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08002223 int resp_buf_type = 0;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002224 __u32 pid = io_parms->pid;
2225 __u16 netfid = io_parms->netfid;
2226 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00002227 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002228 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002229
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04002230 *nbytes = 0;
2231
Joe Perchesb6b38f72010-04-21 03:50:45 +00002232 cFYI(1, "write2 at %lld %d bytes", (long long)offset, count);
Steve Frenchff7feac2005-11-15 16:45:16 -08002233
Steve French4c3130e2008-12-09 00:28:16 +00002234 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07002235 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00002236 } else {
Steve French8cc64c62005-10-03 13:49:43 -07002237 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00002238 if ((offset >> 32) > 0) {
2239 /* can not handle big offset for old srv */
2240 return -EIO;
2241 }
2242 }
Steve French8cc64c62005-10-03 13:49:43 -07002243 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002244 if (rc)
2245 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002246
2247 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
2248 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
2249
Linus Torvalds1da177e2005-04-16 15:20:36 -07002250 /* tcon and ses pointer are checked in smb_init */
2251 if (tcon->ses->server == NULL)
2252 return -ECONNABORTED;
2253
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002254 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002255 pSMB->Fid = netfid;
2256 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00002257 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002258 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002259 pSMB->Reserved = 0xFFFFFFFF;
2260 pSMB->WriteMode = 0;
2261 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002262
Linus Torvalds1da177e2005-04-16 15:20:36 -07002263 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00002264 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002265
Steve French3e844692005-10-03 13:37:24 -07002266 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
2267 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002268 /* header + 1 byte pad */
2269 smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
Steve French790fe572007-07-07 19:25:05 +00002270 if (wct == 14)
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002271 inc_rfc1001_len(pSMB, count + 1);
Steve French8cc64c62005-10-03 13:49:43 -07002272 else /* wct == 12 */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002273 inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
Steve French790fe572007-07-07 19:25:05 +00002274 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002275 pSMB->ByteCount = cpu_to_le16(count + 1);
2276 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00002277 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07002278 (struct smb_com_writex_req *)pSMB;
2279 pSMBW->ByteCount = cpu_to_le16(count + 5);
2280 }
Steve French3e844692005-10-03 13:37:24 -07002281 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00002282 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08002283 iov[0].iov_len = smb_hdr_len + 4;
2284 else /* wct == 12 pad bigger by four bytes */
2285 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00002286
Steve French3e844692005-10-03 13:37:24 -07002287
Steve Frenchec637e32005-12-12 20:53:18 -08002288 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French133672e2007-11-13 22:41:37 +00002289 long_op);
Steve Frencha4544342005-08-24 13:59:35 -07002290 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002291 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002292 cFYI(1, "Send error Write2 = %d", rc);
Steve French790fe572007-07-07 19:25:05 +00002293 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08002294 /* presumably this can not happen, but best to be safe */
2295 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002296 } else {
Steve Frenchad7a2922008-02-07 23:25:02 +00002297 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002298 *nbytes = le16_to_cpu(pSMBr->CountHigh);
2299 *nbytes = (*nbytes) << 16;
2300 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05302301
2302 /*
2303 * Mask off high 16 bits when bytes written as returned by the
2304 * server is greater than bytes requested by the client. OS/2
2305 * servers are known to set incorrect CountHigh values.
2306 */
2307 if (*nbytes > count)
2308 *nbytes &= 0xFFFF;
Steve French50c2f752007-07-13 00:33:32 +00002309 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310
Steve French4b8f9302006-02-26 16:41:18 +00002311/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00002312 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002313 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00002314 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002315 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002316
Steve French50c2f752007-07-13 00:33:32 +00002317 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002318 since file handle passed in no longer valid */
2319
2320 return rc;
2321}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002322
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002323int cifs_lockv(const int xid, struct cifs_tcon *tcon, const __u16 netfid,
2324 const __u8 lock_type, const __u32 num_unlock,
2325 const __u32 num_lock, LOCKING_ANDX_RANGE *buf)
2326{
2327 int rc = 0;
2328 LOCK_REQ *pSMB = NULL;
2329 struct kvec iov[2];
2330 int resp_buf_type;
2331 __u16 count;
2332
2333 cFYI(1, "cifs_lockv num lock %d num unlock %d", num_lock, num_unlock);
2334
2335 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2336 if (rc)
2337 return rc;
2338
2339 pSMB->Timeout = 0;
2340 pSMB->NumberOfLocks = cpu_to_le16(num_lock);
2341 pSMB->NumberOfUnlocks = cpu_to_le16(num_unlock);
2342 pSMB->LockType = lock_type;
2343 pSMB->AndXCommand = 0xFF; /* none */
2344 pSMB->Fid = netfid; /* netfid stays le */
2345
2346 count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2347 inc_rfc1001_len(pSMB, count);
2348 pSMB->ByteCount = cpu_to_le16(count);
2349
2350 iov[0].iov_base = (char *)pSMB;
2351 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 -
2352 (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2353 iov[1].iov_base = (char *)buf;
2354 iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2355
2356 cifs_stats_inc(&tcon->num_locks);
2357 rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP);
2358 if (rc)
2359 cFYI(1, "Send error in cifs_lockv = %d", rc);
2360
2361 return rc;
2362}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002363
Linus Torvalds1da177e2005-04-16 15:20:36 -07002364int
Steve French96daf2b2011-05-27 04:34:02 +00002365CIFSSMBLock(const int xid, struct cifs_tcon *tcon,
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002366 const __u16 smb_file_id, const __u32 netpid, const __u64 len,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002367 const __u64 offset, const __u32 numUnlock,
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002368 const __u32 numLock, const __u8 lockType,
2369 const bool waitFlag, const __u8 oplock_level)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002370{
2371 int rc = 0;
2372 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002373/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002374 int bytes_returned;
2375 int timeout = 0;
2376 __u16 count;
2377
Joe Perchesb6b38f72010-04-21 03:50:45 +00002378 cFYI(1, "CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock);
Steve French46810cb2005-04-28 22:41:09 -07002379 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2380
Linus Torvalds1da177e2005-04-16 15:20:36 -07002381 if (rc)
2382 return rc;
2383
Steve French790fe572007-07-07 19:25:05 +00002384 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Steve French133672e2007-11-13 22:41:37 +00002385 timeout = CIFS_ASYNC_OP; /* no response expected */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002386 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00002387 } else if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00002388 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002389 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
2390 } else {
2391 pSMB->Timeout = 0;
2392 }
2393
2394 pSMB->NumberOfLocks = cpu_to_le16(numLock);
2395 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
2396 pSMB->LockType = lockType;
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002397 pSMB->OplockLevel = oplock_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002398 pSMB->AndXCommand = 0xFF; /* none */
2399 pSMB->Fid = smb_file_id; /* netfid stays le */
2400
Steve French790fe572007-07-07 19:25:05 +00002401 if ((numLock != 0) || (numUnlock != 0)) {
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002402 pSMB->Locks[0].Pid = cpu_to_le16(netpid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002403 /* BB where to store pid high? */
2404 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
2405 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
2406 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
2407 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
2408 count = sizeof(LOCKING_ANDX_RANGE);
2409 } else {
2410 /* oplock break */
2411 count = 0;
2412 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002413 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002414 pSMB->ByteCount = cpu_to_le16(count);
2415
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002416 if (waitFlag) {
2417 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002418 (struct smb_hdr *) pSMB, &bytes_returned);
Steve French133672e2007-11-13 22:41:37 +00002419 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002420 } else {
Steve French133672e2007-11-13 22:41:37 +00002421 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
2422 timeout);
2423 /* SMB buffer freed by function above */
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002424 }
Steve Frencha4544342005-08-24 13:59:35 -07002425 cifs_stats_inc(&tcon->num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002426 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002427 cFYI(1, "Send error in Lock = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002428
Steve French50c2f752007-07-13 00:33:32 +00002429 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002430 since file handle passed in no longer valid */
2431 return rc;
2432}
2433
2434int
Steve French96daf2b2011-05-27 04:34:02 +00002435CIFSSMBPosixLock(const int xid, struct cifs_tcon *tcon,
Pavel Shilovsky4f6bcec2011-10-22 15:33:30 +04002436 const __u16 smb_file_id, const __u32 netpid, const int get_flag,
2437 const __u64 len, struct file_lock *pLockData,
2438 const __u16 lock_type, const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00002439{
2440 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2441 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00002442 struct cifs_posix_lock *parm_data;
2443 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00002444 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00002445 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00002446 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00002447 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00002448 struct kvec iov[1];
Steve French08547b02006-02-28 22:39:25 +00002449
Joe Perchesb6b38f72010-04-21 03:50:45 +00002450 cFYI(1, "Posix Lock");
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002451
Steve French790fe572007-07-07 19:25:05 +00002452 if (pLockData == NULL)
Marcin Slusarzed5f0372008-05-13 04:01:01 +00002453 return -EINVAL;
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002454
Steve French08547b02006-02-28 22:39:25 +00002455 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
2456
2457 if (rc)
2458 return rc;
2459
2460 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
2461
Steve French50c2f752007-07-13 00:33:32 +00002462 params = 6;
Steve French08547b02006-02-28 22:39:25 +00002463 pSMB->MaxSetupCount = 0;
2464 pSMB->Reserved = 0;
2465 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00002466 pSMB->Reserved2 = 0;
2467 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2468 offset = param_offset + params;
2469
Steve French08547b02006-02-28 22:39:25 +00002470 count = sizeof(struct cifs_posix_lock);
2471 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002472 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00002473 pSMB->SetupCount = 1;
2474 pSMB->Reserved3 = 0;
Steve French790fe572007-07-07 19:25:05 +00002475 if (get_flag)
Steve French08547b02006-02-28 22:39:25 +00002476 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2477 else
2478 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2479 byte_count = 3 /* pad */ + params + count;
2480 pSMB->DataCount = cpu_to_le16(count);
2481 pSMB->ParameterCount = cpu_to_le16(params);
2482 pSMB->TotalDataCount = pSMB->DataCount;
2483 pSMB->TotalParameterCount = pSMB->ParameterCount;
2484 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00002485 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00002486 (((char *) &pSMB->hdr.Protocol) + offset);
2487
2488 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00002489 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00002490 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00002491 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00002492 pSMB->Timeout = cpu_to_le32(-1);
2493 } else
2494 pSMB->Timeout = 0;
2495
Pavel Shilovsky4f6bcec2011-10-22 15:33:30 +04002496 parm_data->pid = cpu_to_le32(netpid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002497 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00002498 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00002499
2500 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00002501 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00002502 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
2503 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002504 inc_rfc1001_len(pSMB, byte_count);
Steve French08547b02006-02-28 22:39:25 +00002505 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002506 if (waitFlag) {
2507 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2508 (struct smb_hdr *) pSMBr, &bytes_returned);
2509 } else {
Steve French133672e2007-11-13 22:41:37 +00002510 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002511 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French133672e2007-11-13 22:41:37 +00002512 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
2513 &resp_buf_type, timeout);
2514 pSMB = NULL; /* request buf already freed by SendReceive2. Do
2515 not try to free it twice below on exit */
2516 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002517 }
2518
Steve French08547b02006-02-28 22:39:25 +00002519 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002520 cFYI(1, "Send error in Posix Lock = %d", rc);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002521 } else if (get_flag) {
2522 /* lock structure can be returned on get */
2523 __u16 data_offset;
2524 __u16 data_count;
2525 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00002526
Jeff Layton820a8032011-05-04 08:05:26 -04002527 if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002528 rc = -EIO; /* bad smb */
2529 goto plk_err_exit;
2530 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002531 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2532 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00002533 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002534 rc = -EIO;
2535 goto plk_err_exit;
2536 }
2537 parm_data = (struct cifs_posix_lock *)
2538 ((char *)&pSMBr->hdr.Protocol + data_offset);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002539 if (parm_data->lock_type == __constant_cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002540 pLockData->fl_type = F_UNLCK;
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002541 else {
2542 if (parm_data->lock_type ==
2543 __constant_cpu_to_le16(CIFS_RDLCK))
2544 pLockData->fl_type = F_RDLCK;
2545 else if (parm_data->lock_type ==
2546 __constant_cpu_to_le16(CIFS_WRLCK))
2547 pLockData->fl_type = F_WRLCK;
2548
Steve French5443d132011-03-13 05:08:25 +00002549 pLockData->fl_start = le64_to_cpu(parm_data->start);
2550 pLockData->fl_end = pLockData->fl_start +
2551 le64_to_cpu(parm_data->length) - 1;
2552 pLockData->fl_pid = le32_to_cpu(parm_data->pid);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002553 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002554 }
Steve French50c2f752007-07-13 00:33:32 +00002555
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002556plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00002557 if (pSMB)
2558 cifs_small_buf_release(pSMB);
2559
Steve French133672e2007-11-13 22:41:37 +00002560 if (resp_buf_type == CIFS_SMALL_BUFFER)
2561 cifs_small_buf_release(iov[0].iov_base);
2562 else if (resp_buf_type == CIFS_LARGE_BUFFER)
2563 cifs_buf_release(iov[0].iov_base);
2564
Steve French08547b02006-02-28 22:39:25 +00002565 /* Note: On -EAGAIN error only caller can retry on handle based calls
2566 since file handle passed in no longer valid */
2567
2568 return rc;
2569}
2570
2571
2572int
Steve French96daf2b2011-05-27 04:34:02 +00002573CIFSSMBClose(const int xid, struct cifs_tcon *tcon, int smb_file_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002574{
2575 int rc = 0;
2576 CLOSE_REQ *pSMB = NULL;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002577 cFYI(1, "In CIFSSMBClose");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002578
2579/* do not retry on dead session on close */
2580 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00002581 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002582 return 0;
2583 if (rc)
2584 return rc;
2585
Linus Torvalds1da177e2005-04-16 15:20:36 -07002586 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00002587 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002588 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00002589 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002590 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002591 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00002592 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002593 /* EINTR is expected when user ctl-c to kill app */
Joe Perchesb6b38f72010-04-21 03:50:45 +00002594 cERROR(1, "Send error in Close = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002595 }
2596 }
2597
Linus Torvalds1da177e2005-04-16 15:20:36 -07002598 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00002599 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002600 rc = 0;
2601
2602 return rc;
2603}
2604
2605int
Steve French96daf2b2011-05-27 04:34:02 +00002606CIFSSMBFlush(const int xid, struct cifs_tcon *tcon, int smb_file_id)
Steve Frenchb298f222009-02-21 21:17:43 +00002607{
2608 int rc = 0;
2609 FLUSH_REQ *pSMB = NULL;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002610 cFYI(1, "In CIFSSMBFlush");
Steve Frenchb298f222009-02-21 21:17:43 +00002611
2612 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
2613 if (rc)
2614 return rc;
2615
2616 pSMB->FileID = (__u16) smb_file_id;
2617 pSMB->ByteCount = 0;
2618 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
2619 cifs_stats_inc(&tcon->num_flushes);
2620 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002621 cERROR(1, "Send error in Flush = %d", rc);
Steve Frenchb298f222009-02-21 21:17:43 +00002622
2623 return rc;
2624}
2625
2626int
Steve French96daf2b2011-05-27 04:34:02 +00002627CIFSSMBRename(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002628 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002629 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002630{
2631 int rc = 0;
2632 RENAME_REQ *pSMB = NULL;
2633 RENAME_RSP *pSMBr = NULL;
2634 int bytes_returned;
2635 int name_len, name_len2;
2636 __u16 count;
2637
Joe Perchesb6b38f72010-04-21 03:50:45 +00002638 cFYI(1, "In CIFSSMBRename");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002639renameRetry:
2640 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
2641 (void **) &pSMBr);
2642 if (rc)
2643 return rc;
2644
2645 pSMB->BufferFormat = 0x04;
2646 pSMB->SearchAttributes =
2647 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2648 ATTR_DIRECTORY);
2649
2650 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2651 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002652 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002653 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002654 name_len++; /* trailing null */
2655 name_len *= 2;
2656 pSMB->OldFileName[name_len] = 0x04; /* pad */
2657 /* protocol requires ASCII signature byte on Unicode string */
2658 pSMB->OldFileName[name_len + 1] = 0x00;
2659 name_len2 =
Steve French582d21e2008-05-13 04:54:12 +00002660 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002661 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002662 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2663 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002664 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002665 name_len = strnlen(fromName, PATH_MAX);
2666 name_len++; /* trailing null */
2667 strncpy(pSMB->OldFileName, fromName, name_len);
2668 name_len2 = strnlen(toName, PATH_MAX);
2669 name_len2++; /* trailing null */
2670 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2671 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2672 name_len2++; /* trailing null */
2673 name_len2++; /* signature byte */
2674 }
2675
2676 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002677 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002678 pSMB->ByteCount = cpu_to_le16(count);
2679
2680 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2681 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002682 cifs_stats_inc(&tcon->num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002683 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002684 cFYI(1, "Send error in rename = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002685
Linus Torvalds1da177e2005-04-16 15:20:36 -07002686 cifs_buf_release(pSMB);
2687
2688 if (rc == -EAGAIN)
2689 goto renameRetry;
2690
2691 return rc;
2692}
2693
Steve French96daf2b2011-05-27 04:34:02 +00002694int CIFSSMBRenameOpenFile(const int xid, struct cifs_tcon *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002695 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002696 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697{
2698 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2699 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002700 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002701 char *data_offset;
2702 char dummy_string[30];
2703 int rc = 0;
2704 int bytes_returned = 0;
2705 int len_of_str;
2706 __u16 params, param_offset, offset, count, byte_count;
2707
Joe Perchesb6b38f72010-04-21 03:50:45 +00002708 cFYI(1, "Rename to File by handle");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002709 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2710 (void **) &pSMBr);
2711 if (rc)
2712 return rc;
2713
2714 params = 6;
2715 pSMB->MaxSetupCount = 0;
2716 pSMB->Reserved = 0;
2717 pSMB->Flags = 0;
2718 pSMB->Timeout = 0;
2719 pSMB->Reserved2 = 0;
2720 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2721 offset = param_offset + params;
2722
2723 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2724 rename_info = (struct set_file_rename *) data_offset;
2725 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002726 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002727 pSMB->SetupCount = 1;
2728 pSMB->Reserved3 = 0;
2729 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2730 byte_count = 3 /* pad */ + params;
2731 pSMB->ParameterCount = cpu_to_le16(params);
2732 pSMB->TotalParameterCount = pSMB->ParameterCount;
2733 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2734 pSMB->DataOffset = cpu_to_le16(offset);
2735 /* construct random name ".cifs_tmp<inodenum><mid>" */
2736 rename_info->overwrite = cpu_to_le32(1);
2737 rename_info->root_fid = 0;
2738 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002739 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002740 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
2741 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002742 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002743 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05002744 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002745 target_name, PATH_MAX, nls_codepage,
2746 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002747 }
2748 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002749 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002750 byte_count += count;
2751 pSMB->DataCount = cpu_to_le16(count);
2752 pSMB->TotalDataCount = pSMB->DataCount;
2753 pSMB->Fid = netfid;
2754 pSMB->InformationLevel =
2755 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2756 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002757 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002758 pSMB->ByteCount = cpu_to_le16(byte_count);
2759 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002760 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002761 cifs_stats_inc(&pTcon->num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002762 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002763 cFYI(1, "Send error in Rename (by file handle) = %d", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07002764
Linus Torvalds1da177e2005-04-16 15:20:36 -07002765 cifs_buf_release(pSMB);
2766
2767 /* Note: On -EAGAIN error only caller can retry on handle based calls
2768 since file handle passed in no longer valid */
2769
2770 return rc;
2771}
2772
2773int
Steve French96daf2b2011-05-27 04:34:02 +00002774CIFSSMBCopy(const int xid, struct cifs_tcon *tcon, const char *fromName,
Steve French50c2f752007-07-13 00:33:32 +00002775 const __u16 target_tid, const char *toName, const int flags,
2776 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002777{
2778 int rc = 0;
2779 COPY_REQ *pSMB = NULL;
2780 COPY_RSP *pSMBr = NULL;
2781 int bytes_returned;
2782 int name_len, name_len2;
2783 __u16 count;
2784
Joe Perchesb6b38f72010-04-21 03:50:45 +00002785 cFYI(1, "In CIFSSMBCopy");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002786copyRetry:
2787 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2788 (void **) &pSMBr);
2789 if (rc)
2790 return rc;
2791
2792 pSMB->BufferFormat = 0x04;
2793 pSMB->Tid2 = target_tid;
2794
2795 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2796
2797 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00002798 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07002799 fromName, PATH_MAX, nls_codepage,
2800 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002801 name_len++; /* trailing null */
2802 name_len *= 2;
2803 pSMB->OldFileName[name_len] = 0x04; /* pad */
2804 /* protocol requires ASCII signature byte on Unicode string */
2805 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002806 name_len2 =
2807 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002808 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002809 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2810 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002811 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002812 name_len = strnlen(fromName, PATH_MAX);
2813 name_len++; /* trailing null */
2814 strncpy(pSMB->OldFileName, fromName, name_len);
2815 name_len2 = strnlen(toName, PATH_MAX);
2816 name_len2++; /* trailing null */
2817 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2818 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2819 name_len2++; /* trailing null */
2820 name_len2++; /* signature byte */
2821 }
2822
2823 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002824 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002825 pSMB->ByteCount = cpu_to_le16(count);
2826
2827 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2828 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2829 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002830 cFYI(1, "Send error in copy = %d with %d files copied",
2831 rc, le16_to_cpu(pSMBr->CopyCount));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832 }
Steve French0d817bc2008-05-22 02:02:03 +00002833 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002834
2835 if (rc == -EAGAIN)
2836 goto copyRetry;
2837
2838 return rc;
2839}
2840
2841int
Steve French96daf2b2011-05-27 04:34:02 +00002842CIFSUnixCreateSymLink(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002843 const char *fromName, const char *toName,
2844 const struct nls_table *nls_codepage)
2845{
2846 TRANSACTION2_SPI_REQ *pSMB = NULL;
2847 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2848 char *data_offset;
2849 int name_len;
2850 int name_len_target;
2851 int rc = 0;
2852 int bytes_returned = 0;
2853 __u16 params, param_offset, offset, byte_count;
2854
Joe Perchesb6b38f72010-04-21 03:50:45 +00002855 cFYI(1, "In Symlink Unix style");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002856createSymLinkRetry:
2857 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2858 (void **) &pSMBr);
2859 if (rc)
2860 return rc;
2861
2862 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2863 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002864 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002865 /* find define for this maxpathcomponent */
2866 , nls_codepage);
2867 name_len++; /* trailing null */
2868 name_len *= 2;
2869
Steve French50c2f752007-07-13 00:33:32 +00002870 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002871 name_len = strnlen(fromName, PATH_MAX);
2872 name_len++; /* trailing null */
2873 strncpy(pSMB->FileName, fromName, name_len);
2874 }
2875 params = 6 + name_len;
2876 pSMB->MaxSetupCount = 0;
2877 pSMB->Reserved = 0;
2878 pSMB->Flags = 0;
2879 pSMB->Timeout = 0;
2880 pSMB->Reserved2 = 0;
2881 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002882 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002883 offset = param_offset + params;
2884
2885 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2886 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2887 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08002888 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002889 /* find define for this maxpathcomponent */
2890 , nls_codepage);
2891 name_len_target++; /* trailing null */
2892 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002893 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002894 name_len_target = strnlen(toName, PATH_MAX);
2895 name_len_target++; /* trailing null */
2896 strncpy(data_offset, toName, name_len_target);
2897 }
2898
2899 pSMB->MaxParameterCount = cpu_to_le16(2);
2900 /* BB find exact max on data count below from sess */
2901 pSMB->MaxDataCount = cpu_to_le16(1000);
2902 pSMB->SetupCount = 1;
2903 pSMB->Reserved3 = 0;
2904 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2905 byte_count = 3 /* pad */ + params + name_len_target;
2906 pSMB->DataCount = cpu_to_le16(name_len_target);
2907 pSMB->ParameterCount = cpu_to_le16(params);
2908 pSMB->TotalDataCount = pSMB->DataCount;
2909 pSMB->TotalParameterCount = pSMB->ParameterCount;
2910 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2911 pSMB->DataOffset = cpu_to_le16(offset);
2912 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2913 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002914 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002915 pSMB->ByteCount = cpu_to_le16(byte_count);
2916 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2917 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002918 cifs_stats_inc(&tcon->num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002919 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002920 cFYI(1, "Send error in SetPathInfo create symlink = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002921
Steve French0d817bc2008-05-22 02:02:03 +00002922 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002923
2924 if (rc == -EAGAIN)
2925 goto createSymLinkRetry;
2926
2927 return rc;
2928}
2929
2930int
Steve French96daf2b2011-05-27 04:34:02 +00002931CIFSUnixCreateHardLink(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002932 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002933 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002934{
2935 TRANSACTION2_SPI_REQ *pSMB = NULL;
2936 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2937 char *data_offset;
2938 int name_len;
2939 int name_len_target;
2940 int rc = 0;
2941 int bytes_returned = 0;
2942 __u16 params, param_offset, offset, byte_count;
2943
Joe Perchesb6b38f72010-04-21 03:50:45 +00002944 cFYI(1, "In Create Hard link Unix style");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002945createHardLinkRetry:
2946 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2947 (void **) &pSMBr);
2948 if (rc)
2949 return rc;
2950
2951 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05002952 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07002953 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002954 name_len++; /* trailing null */
2955 name_len *= 2;
2956
Steve French50c2f752007-07-13 00:33:32 +00002957 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002958 name_len = strnlen(toName, PATH_MAX);
2959 name_len++; /* trailing null */
2960 strncpy(pSMB->FileName, toName, name_len);
2961 }
2962 params = 6 + name_len;
2963 pSMB->MaxSetupCount = 0;
2964 pSMB->Reserved = 0;
2965 pSMB->Flags = 0;
2966 pSMB->Timeout = 0;
2967 pSMB->Reserved2 = 0;
2968 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002969 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002970 offset = param_offset + params;
2971
2972 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2973 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2974 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05002975 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07002976 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002977 name_len_target++; /* trailing null */
2978 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002979 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002980 name_len_target = strnlen(fromName, PATH_MAX);
2981 name_len_target++; /* trailing null */
2982 strncpy(data_offset, fromName, name_len_target);
2983 }
2984
2985 pSMB->MaxParameterCount = cpu_to_le16(2);
2986 /* BB find exact max on data count below from sess*/
2987 pSMB->MaxDataCount = cpu_to_le16(1000);
2988 pSMB->SetupCount = 1;
2989 pSMB->Reserved3 = 0;
2990 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2991 byte_count = 3 /* pad */ + params + name_len_target;
2992 pSMB->ParameterCount = cpu_to_le16(params);
2993 pSMB->TotalParameterCount = pSMB->ParameterCount;
2994 pSMB->DataCount = cpu_to_le16(name_len_target);
2995 pSMB->TotalDataCount = pSMB->DataCount;
2996 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2997 pSMB->DataOffset = cpu_to_le16(offset);
2998 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2999 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003000 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003001 pSMB->ByteCount = cpu_to_le16(byte_count);
3002 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3003 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003004 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00003005 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003006 cFYI(1, "Send error in SetPathInfo (hard link) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003007
3008 cifs_buf_release(pSMB);
3009 if (rc == -EAGAIN)
3010 goto createHardLinkRetry;
3011
3012 return rc;
3013}
3014
3015int
Steve French96daf2b2011-05-27 04:34:02 +00003016CIFSCreateHardLink(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003017 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07003018 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003019{
3020 int rc = 0;
3021 NT_RENAME_REQ *pSMB = NULL;
3022 RENAME_RSP *pSMBr = NULL;
3023 int bytes_returned;
3024 int name_len, name_len2;
3025 __u16 count;
3026
Joe Perchesb6b38f72010-04-21 03:50:45 +00003027 cFYI(1, "In CIFSCreateHardLink");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003028winCreateHardLinkRetry:
3029
3030 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
3031 (void **) &pSMBr);
3032 if (rc)
3033 return rc;
3034
3035 pSMB->SearchAttributes =
3036 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3037 ATTR_DIRECTORY);
3038 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
3039 pSMB->ClusterCount = 0;
3040
3041 pSMB->BufferFormat = 0x04;
3042
3043 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3044 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003045 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07003046 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003047 name_len++; /* trailing null */
3048 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05003049
3050 /* protocol specifies ASCII buffer format (0x04) for unicode */
3051 pSMB->OldFileName[name_len] = 0x04;
3052 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003053 name_len2 =
Steve French50c2f752007-07-13 00:33:32 +00003054 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07003055 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003056 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
3057 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00003058 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003059 name_len = strnlen(fromName, PATH_MAX);
3060 name_len++; /* trailing null */
3061 strncpy(pSMB->OldFileName, fromName, name_len);
3062 name_len2 = strnlen(toName, PATH_MAX);
3063 name_len2++; /* trailing null */
3064 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
3065 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
3066 name_len2++; /* trailing null */
3067 name_len2++; /* signature byte */
3068 }
3069
3070 count = 1 /* string type byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003071 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003072 pSMB->ByteCount = cpu_to_le16(count);
3073
3074 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3075 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003076 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00003077 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003078 cFYI(1, "Send error in hard link (NT rename) = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00003079
Linus Torvalds1da177e2005-04-16 15:20:36 -07003080 cifs_buf_release(pSMB);
3081 if (rc == -EAGAIN)
3082 goto winCreateHardLinkRetry;
3083
3084 return rc;
3085}
3086
3087int
Steve French96daf2b2011-05-27 04:34:02 +00003088CIFSSMBUnixQuerySymLink(const int xid, struct cifs_tcon *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04003089 const unsigned char *searchName, char **symlinkinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003090 const struct nls_table *nls_codepage)
3091{
3092/* SMB_QUERY_FILE_UNIX_LINK */
3093 TRANSACTION2_QPI_REQ *pSMB = NULL;
3094 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3095 int rc = 0;
3096 int bytes_returned;
3097 int name_len;
3098 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04003099 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003100
Joe Perchesb6b38f72010-04-21 03:50:45 +00003101 cFYI(1, "In QPathSymLinkInfo (Unix) for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003102
3103querySymLinkRetry:
3104 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3105 (void **) &pSMBr);
3106 if (rc)
3107 return rc;
3108
3109 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3110 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003111 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
3112 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003113 name_len++; /* trailing null */
3114 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003115 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003116 name_len = strnlen(searchName, PATH_MAX);
3117 name_len++; /* trailing null */
3118 strncpy(pSMB->FileName, searchName, name_len);
3119 }
3120
3121 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3122 pSMB->TotalDataCount = 0;
3123 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04003124 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003125 pSMB->MaxSetupCount = 0;
3126 pSMB->Reserved = 0;
3127 pSMB->Flags = 0;
3128 pSMB->Timeout = 0;
3129 pSMB->Reserved2 = 0;
3130 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003131 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003132 pSMB->DataCount = 0;
3133 pSMB->DataOffset = 0;
3134 pSMB->SetupCount = 1;
3135 pSMB->Reserved3 = 0;
3136 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3137 byte_count = params + 1 /* pad */ ;
3138 pSMB->TotalParameterCount = cpu_to_le16(params);
3139 pSMB->ParameterCount = pSMB->TotalParameterCount;
3140 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
3141 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003142 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003143 pSMB->ByteCount = cpu_to_le16(byte_count);
3144
3145 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3146 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3147 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003148 cFYI(1, "Send error in QuerySymLinkInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003149 } else {
3150 /* decode response */
3151
3152 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003153 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003154 if (rc || get_bcc(&pSMBr->hdr) < 2)
Jeff Layton460b9692009-04-30 07:17:56 -04003155 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003156 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00003157 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04003158 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003159
Jeff Layton460b9692009-04-30 07:17:56 -04003160 data_start = ((char *) &pSMBr->hdr.Protocol) +
3161 le16_to_cpu(pSMBr->t2.DataOffset);
3162
Steve French0e0d2cf2009-05-01 05:27:32 +00003163 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3164 is_unicode = true;
3165 else
3166 is_unicode = false;
3167
Steve French737b7582005-04-28 22:41:06 -07003168 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchd185cda2009-04-30 17:45:10 +00003169 *symlinkinfo = cifs_strndup_from_ucs(data_start, count,
Steve French0e0d2cf2009-05-01 05:27:32 +00003170 is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04003171 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04003172 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003173 }
3174 }
3175 cifs_buf_release(pSMB);
3176 if (rc == -EAGAIN)
3177 goto querySymLinkRetry;
3178 return rc;
3179}
3180
Steve Frenchc52a9552011-02-24 06:16:22 +00003181#ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL
3182/*
3183 * Recent Windows versions now create symlinks more frequently
3184 * and they use the "reparse point" mechanism below. We can of course
3185 * do symlinks nicely to Samba and other servers which support the
3186 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
3187 * "MF" symlinks optionally, but for recent Windows we really need to
3188 * reenable the code below and fix the cifs_symlink callers to handle this.
3189 * In the interim this code has been moved to its own config option so
3190 * it is not compiled in by default until callers fixed up and more tested.
3191 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003192int
Steve French96daf2b2011-05-27 04:34:02 +00003193CIFSSMBQueryReparseLinkInfo(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003194 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00003195 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003196 const struct nls_table *nls_codepage)
3197{
3198 int rc = 0;
3199 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00003200 struct smb_com_transaction_ioctl_req *pSMB;
3201 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003202
Joe Perchesb6b38f72010-04-21 03:50:45 +00003203 cFYI(1, "In Windows reparse style QueryLink for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003204 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3205 (void **) &pSMBr);
3206 if (rc)
3207 return rc;
3208
3209 pSMB->TotalParameterCount = 0 ;
3210 pSMB->TotalDataCount = 0;
3211 pSMB->MaxParameterCount = cpu_to_le32(2);
3212 /* BB find exact data count max from sess structure BB */
Jeff Laytonc974bef2011-10-11 06:41:32 -04003213 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003214 pSMB->MaxSetupCount = 4;
3215 pSMB->Reserved = 0;
3216 pSMB->ParameterOffset = 0;
3217 pSMB->DataCount = 0;
3218 pSMB->DataOffset = 0;
3219 pSMB->SetupCount = 4;
3220 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
3221 pSMB->ParameterCount = pSMB->TotalParameterCount;
3222 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
3223 pSMB->IsFsctl = 1; /* FSCTL */
3224 pSMB->IsRootFlag = 0;
3225 pSMB->Fid = fid; /* file handle always le */
3226 pSMB->ByteCount = 0;
3227
3228 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3229 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3230 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003231 cFYI(1, "Send error in QueryReparseLinkInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003232 } else { /* decode response */
3233 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
3234 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
Jeff Layton820a8032011-05-04 08:05:26 -04003235 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
3236 /* BB also check enough total bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003237 rc = -EIO; /* bad smb */
Steve Frenchafe48c32009-05-02 05:25:46 +00003238 goto qreparse_out;
3239 }
3240 if (data_count && (data_count < 2048)) {
3241 char *end_of_smb = 2 /* sizeof byte count */ +
Jeff Layton820a8032011-05-04 08:05:26 -04003242 get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003243
Steve Frenchafe48c32009-05-02 05:25:46 +00003244 struct reparse_data *reparse_buf =
Steve French50c2f752007-07-13 00:33:32 +00003245 (struct reparse_data *)
3246 ((char *)&pSMBr->hdr.Protocol
3247 + data_offset);
Steve Frenchafe48c32009-05-02 05:25:46 +00003248 if ((char *)reparse_buf >= end_of_smb) {
3249 rc = -EIO;
3250 goto qreparse_out;
3251 }
3252 if ((reparse_buf->LinkNamesBuf +
3253 reparse_buf->TargetNameOffset +
3254 reparse_buf->TargetNameLen) > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003255 cFYI(1, "reparse buf beyond SMB");
Steve Frenchafe48c32009-05-02 05:25:46 +00003256 rc = -EIO;
3257 goto qreparse_out;
3258 }
Steve French50c2f752007-07-13 00:33:32 +00003259
Steve Frenchafe48c32009-05-02 05:25:46 +00003260 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3261 cifs_from_ucs2(symlinkinfo, (__le16 *)
Steve French50c2f752007-07-13 00:33:32 +00003262 (reparse_buf->LinkNamesBuf +
3263 reparse_buf->TargetNameOffset),
Steve Frenchafe48c32009-05-02 05:25:46 +00003264 buflen,
3265 reparse_buf->TargetNameLen,
3266 nls_codepage, 0);
3267 } else { /* ASCII names */
3268 strncpy(symlinkinfo,
3269 reparse_buf->LinkNamesBuf +
3270 reparse_buf->TargetNameOffset,
3271 min_t(const int, buflen,
3272 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003273 }
Steve Frenchafe48c32009-05-02 05:25:46 +00003274 } else {
3275 rc = -EIO;
Joe Perchesb6b38f72010-04-21 03:50:45 +00003276 cFYI(1, "Invalid return data count on "
3277 "get reparse info ioctl");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003278 }
Steve Frenchafe48c32009-05-02 05:25:46 +00003279 symlinkinfo[buflen] = 0; /* just in case so the caller
3280 does not go off the end of the buffer */
Joe Perchesb6b38f72010-04-21 03:50:45 +00003281 cFYI(1, "readlink result - %s", symlinkinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003282 }
Steve French989c7e52009-05-02 05:32:20 +00003283
Linus Torvalds1da177e2005-04-16 15:20:36 -07003284qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07003285 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003286
3287 /* Note: On -EAGAIN error only caller can retry on handle based calls
3288 since file handle passed in no longer valid */
3289
3290 return rc;
3291}
Steve Frenchc52a9552011-02-24 06:16:22 +00003292#endif /* CIFS_SYMLINK_EXPERIMENTAL */ /* BB temporarily unused */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003293
3294#ifdef CONFIG_CIFS_POSIX
3295
3296/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00003297static void cifs_convert_ace(posix_acl_xattr_entry *ace,
3298 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003299{
3300 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08003301 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
3302 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
3303 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesb6b38f72010-04-21 03:50:45 +00003304 /* cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003305
3306 return;
3307}
3308
3309/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00003310static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
3311 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003312{
3313 int size = 0;
3314 int i;
3315 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00003316 struct cifs_posix_ace *pACE;
3317 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
3318 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003319
3320 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
3321 return -EOPNOTSUPP;
3322
Steve French790fe572007-07-07 19:25:05 +00003323 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003324 count = le16_to_cpu(cifs_acl->access_entry_count);
3325 pACE = &cifs_acl->ace_array[0];
3326 size = sizeof(struct cifs_posix_acl);
3327 size += sizeof(struct cifs_posix_ace) * count;
3328 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003329 if (size_of_data_area < size) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003330 cFYI(1, "bad CIFS POSIX ACL size %d vs. %d",
3331 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003332 return -EINVAL;
3333 }
Steve French790fe572007-07-07 19:25:05 +00003334 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003335 count = le16_to_cpu(cifs_acl->access_entry_count);
3336 size = sizeof(struct cifs_posix_acl);
3337 size += sizeof(struct cifs_posix_ace) * count;
3338/* skip past access ACEs to get to default ACEs */
3339 pACE = &cifs_acl->ace_array[count];
3340 count = le16_to_cpu(cifs_acl->default_entry_count);
3341 size += sizeof(struct cifs_posix_ace) * count;
3342 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003343 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003344 return -EINVAL;
3345 } else {
3346 /* illegal type */
3347 return -EINVAL;
3348 }
3349
3350 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00003351 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00003352 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00003353 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003354 return -ERANGE;
3355 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08003356 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00003357 for (i = 0; i < count ; i++) {
3358 cifs_convert_ace(&local_acl->a_entries[i], pACE);
3359 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003360 }
3361 }
3362 return size;
3363}
3364
Steve French50c2f752007-07-13 00:33:32 +00003365static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
3366 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003367{
3368 __u16 rc = 0; /* 0 = ACL converted ok */
3369
Steve Frenchff7feac2005-11-15 16:45:16 -08003370 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
3371 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003372 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00003373 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003374 /* Probably no need to le convert -1 on any arch but can not hurt */
3375 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00003376 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08003377 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesb6b38f72010-04-21 03:50:45 +00003378 /*cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id);*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003379 return rc;
3380}
3381
3382/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00003383static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
3384 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003385{
3386 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00003387 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
3388 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003389 int count;
3390 int i;
3391
Steve French790fe572007-07-07 19:25:05 +00003392 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003393 return 0;
3394
3395 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesb6b38f72010-04-21 03:50:45 +00003396 cFYI(1, "setting acl with %d entries from buf of length %d and "
Steve French63135e02007-07-17 17:34:02 +00003397 "version of %d",
Joe Perchesb6b38f72010-04-21 03:50:45 +00003398 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00003399 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003400 cFYI(1, "unknown POSIX ACL version %d",
3401 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003402 return 0;
3403 }
3404 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00003405 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08003406 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00003407 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08003408 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003409 else {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003410 cFYI(1, "unknown ACL type %d", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003411 return 0;
3412 }
Steve French50c2f752007-07-13 00:33:32 +00003413 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003414 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
3415 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00003416 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003417 /* ACE not converted */
3418 break;
3419 }
3420 }
Steve French790fe572007-07-07 19:25:05 +00003421 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003422 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
3423 rc += sizeof(struct cifs_posix_acl);
3424 /* BB add check to make sure ACL does not overflow SMB */
3425 }
3426 return rc;
3427}
3428
3429int
Steve French96daf2b2011-05-27 04:34:02 +00003430CIFSSMBGetPosixACL(const int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003431 const unsigned char *searchName,
3432 char *acl_inf, const int buflen, const int acl_type,
3433 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003434{
3435/* SMB_QUERY_POSIX_ACL */
3436 TRANSACTION2_QPI_REQ *pSMB = NULL;
3437 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3438 int rc = 0;
3439 int bytes_returned;
3440 int name_len;
3441 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00003442
Joe Perchesb6b38f72010-04-21 03:50:45 +00003443 cFYI(1, "In GetPosixACL (Unix) for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003444
3445queryAclRetry:
3446 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3447 (void **) &pSMBr);
3448 if (rc)
3449 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003450
Linus Torvalds1da177e2005-04-16 15:20:36 -07003451 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3452 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003453 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003454 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003455 name_len++; /* trailing null */
3456 name_len *= 2;
3457 pSMB->FileName[name_len] = 0;
3458 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00003459 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003460 name_len = strnlen(searchName, PATH_MAX);
3461 name_len++; /* trailing null */
3462 strncpy(pSMB->FileName, searchName, name_len);
3463 }
3464
3465 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3466 pSMB->TotalDataCount = 0;
3467 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00003468 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003469 pSMB->MaxDataCount = cpu_to_le16(4000);
3470 pSMB->MaxSetupCount = 0;
3471 pSMB->Reserved = 0;
3472 pSMB->Flags = 0;
3473 pSMB->Timeout = 0;
3474 pSMB->Reserved2 = 0;
3475 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003476 offsetof(struct smb_com_transaction2_qpi_req,
3477 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003478 pSMB->DataCount = 0;
3479 pSMB->DataOffset = 0;
3480 pSMB->SetupCount = 1;
3481 pSMB->Reserved3 = 0;
3482 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3483 byte_count = params + 1 /* pad */ ;
3484 pSMB->TotalParameterCount = cpu_to_le16(params);
3485 pSMB->ParameterCount = pSMB->TotalParameterCount;
3486 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
3487 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003488 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003489 pSMB->ByteCount = cpu_to_le16(byte_count);
3490
3491 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3492 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08003493 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003494 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003495 cFYI(1, "Send error in Query POSIX ACL = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003496 } else {
3497 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00003498
Linus Torvalds1da177e2005-04-16 15:20:36 -07003499 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003500 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003501 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003502 rc = -EIO; /* bad smb */
3503 else {
3504 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3505 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3506 rc = cifs_copy_posix_acl(acl_inf,
3507 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00003508 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003509 }
3510 }
3511 cifs_buf_release(pSMB);
3512 if (rc == -EAGAIN)
3513 goto queryAclRetry;
3514 return rc;
3515}
3516
3517int
Steve French96daf2b2011-05-27 04:34:02 +00003518CIFSSMBSetPosixACL(const int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003519 const unsigned char *fileName,
3520 const char *local_acl, const int buflen,
3521 const int acl_type,
3522 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003523{
3524 struct smb_com_transaction2_spi_req *pSMB = NULL;
3525 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3526 char *parm_data;
3527 int name_len;
3528 int rc = 0;
3529 int bytes_returned = 0;
3530 __u16 params, byte_count, data_count, param_offset, offset;
3531
Joe Perchesb6b38f72010-04-21 03:50:45 +00003532 cFYI(1, "In SetPosixACL (Unix) for path %s", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003533setAclRetry:
3534 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003535 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003536 if (rc)
3537 return rc;
3538 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3539 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003540 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07003541 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003542 name_len++; /* trailing null */
3543 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003544 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003545 name_len = strnlen(fileName, PATH_MAX);
3546 name_len++; /* trailing null */
3547 strncpy(pSMB->FileName, fileName, name_len);
3548 }
3549 params = 6 + name_len;
3550 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003551 /* BB find max SMB size from sess */
3552 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003553 pSMB->MaxSetupCount = 0;
3554 pSMB->Reserved = 0;
3555 pSMB->Flags = 0;
3556 pSMB->Timeout = 0;
3557 pSMB->Reserved2 = 0;
3558 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003559 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003560 offset = param_offset + params;
3561 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
3562 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3563
3564 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00003565 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003566
Steve French790fe572007-07-07 19:25:05 +00003567 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003568 rc = -EOPNOTSUPP;
3569 goto setACLerrorExit;
3570 }
3571 pSMB->DataOffset = cpu_to_le16(offset);
3572 pSMB->SetupCount = 1;
3573 pSMB->Reserved3 = 0;
3574 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3575 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
3576 byte_count = 3 /* pad */ + params + data_count;
3577 pSMB->DataCount = cpu_to_le16(data_count);
3578 pSMB->TotalDataCount = pSMB->DataCount;
3579 pSMB->ParameterCount = cpu_to_le16(params);
3580 pSMB->TotalParameterCount = pSMB->ParameterCount;
3581 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003582 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003583 pSMB->ByteCount = cpu_to_le16(byte_count);
3584 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003585 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003586 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003587 cFYI(1, "Set POSIX ACL returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003588
3589setACLerrorExit:
3590 cifs_buf_release(pSMB);
3591 if (rc == -EAGAIN)
3592 goto setAclRetry;
3593 return rc;
3594}
3595
Steve Frenchf654bac2005-04-28 22:41:04 -07003596/* BB fix tabs in this function FIXME BB */
3597int
Steve French96daf2b2011-05-27 04:34:02 +00003598CIFSGetExtAttr(const int xid, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00003599 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07003600{
Steve French50c2f752007-07-13 00:33:32 +00003601 int rc = 0;
3602 struct smb_t2_qfi_req *pSMB = NULL;
3603 struct smb_t2_qfi_rsp *pSMBr = NULL;
3604 int bytes_returned;
3605 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07003606
Joe Perchesb6b38f72010-04-21 03:50:45 +00003607 cFYI(1, "In GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00003608 if (tcon == NULL)
3609 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07003610
3611GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003612 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3613 (void **) &pSMBr);
3614 if (rc)
3615 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003616
Steve Frenchad7a2922008-02-07 23:25:02 +00003617 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003618 pSMB->t2.TotalDataCount = 0;
3619 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3620 /* BB find exact max data count below from sess structure BB */
3621 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3622 pSMB->t2.MaxSetupCount = 0;
3623 pSMB->t2.Reserved = 0;
3624 pSMB->t2.Flags = 0;
3625 pSMB->t2.Timeout = 0;
3626 pSMB->t2.Reserved2 = 0;
3627 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3628 Fid) - 4);
3629 pSMB->t2.DataCount = 0;
3630 pSMB->t2.DataOffset = 0;
3631 pSMB->t2.SetupCount = 1;
3632 pSMB->t2.Reserved3 = 0;
3633 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3634 byte_count = params + 1 /* pad */ ;
3635 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3636 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3637 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3638 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003639 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003640 inc_rfc1001_len(pSMB, byte_count);
Steve French790fe572007-07-07 19:25:05 +00003641 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003642
Steve French790fe572007-07-07 19:25:05 +00003643 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3644 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3645 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003646 cFYI(1, "error %d in GetExtAttr", rc);
Steve French790fe572007-07-07 19:25:05 +00003647 } else {
3648 /* decode response */
3649 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003650 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003651 if (rc || get_bcc(&pSMBr->hdr) < 2)
Steve French790fe572007-07-07 19:25:05 +00003652 /* If rc should we check for EOPNOSUPP and
3653 disable the srvino flag? or in caller? */
3654 rc = -EIO; /* bad smb */
3655 else {
3656 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3657 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3658 struct file_chattr_info *pfinfo;
3659 /* BB Do we need a cast or hash here ? */
3660 if (count != 16) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003661 cFYI(1, "Illegal size ret in GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00003662 rc = -EIO;
3663 goto GetExtAttrOut;
3664 }
3665 pfinfo = (struct file_chattr_info *)
3666 (data_offset + (char *) &pSMBr->hdr.Protocol);
3667 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003668 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003669 }
3670 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003671GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003672 cifs_buf_release(pSMB);
3673 if (rc == -EAGAIN)
3674 goto GetExtAttrRetry;
3675 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003676}
3677
Steve Frenchf654bac2005-04-28 22:41:04 -07003678#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003679
Jeff Layton79df1ba2010-12-06 12:52:08 -05003680#ifdef CONFIG_CIFS_ACL
3681/*
3682 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3683 * all NT TRANSACTS that we init here have total parm and data under about 400
3684 * bytes (to fit in small cifs buffer size), which is the case so far, it
3685 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3686 * returned setup area) and MaxParameterCount (returned parms size) must be set
3687 * by caller
3688 */
3689static int
3690smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French96daf2b2011-05-27 04:34:02 +00003691 const int parm_len, struct cifs_tcon *tcon,
Jeff Layton79df1ba2010-12-06 12:52:08 -05003692 void **ret_buf)
3693{
3694 int rc;
3695 __u32 temp_offset;
3696 struct smb_com_ntransact_req *pSMB;
3697
3698 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3699 (void **)&pSMB);
3700 if (rc)
3701 return rc;
3702 *ret_buf = (void *)pSMB;
3703 pSMB->Reserved = 0;
3704 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3705 pSMB->TotalDataCount = 0;
Jeff Laytonc974bef2011-10-11 06:41:32 -04003706 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003707 pSMB->ParameterCount = pSMB->TotalParameterCount;
3708 pSMB->DataCount = pSMB->TotalDataCount;
3709 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3710 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3711 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3712 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3713 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3714 pSMB->SubCommand = cpu_to_le16(sub_command);
3715 return 0;
3716}
3717
3718static int
3719validate_ntransact(char *buf, char **ppparm, char **ppdata,
3720 __u32 *pparmlen, __u32 *pdatalen)
3721{
3722 char *end_of_smb;
3723 __u32 data_count, data_offset, parm_count, parm_offset;
3724 struct smb_com_ntransact_rsp *pSMBr;
Jeff Layton820a8032011-05-04 08:05:26 -04003725 u16 bcc;
Jeff Layton79df1ba2010-12-06 12:52:08 -05003726
3727 *pdatalen = 0;
3728 *pparmlen = 0;
3729
3730 if (buf == NULL)
3731 return -EINVAL;
3732
3733 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3734
Jeff Layton820a8032011-05-04 08:05:26 -04003735 bcc = get_bcc(&pSMBr->hdr);
3736 end_of_smb = 2 /* sizeof byte count */ + bcc +
Jeff Layton79df1ba2010-12-06 12:52:08 -05003737 (char *)&pSMBr->ByteCount;
3738
3739 data_offset = le32_to_cpu(pSMBr->DataOffset);
3740 data_count = le32_to_cpu(pSMBr->DataCount);
3741 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3742 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3743
3744 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3745 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3746
3747 /* should we also check that parm and data areas do not overlap? */
3748 if (*ppparm > end_of_smb) {
3749 cFYI(1, "parms start after end of smb");
3750 return -EINVAL;
3751 } else if (parm_count + *ppparm > end_of_smb) {
3752 cFYI(1, "parm end after end of smb");
3753 return -EINVAL;
3754 } else if (*ppdata > end_of_smb) {
3755 cFYI(1, "data starts after end of smb");
3756 return -EINVAL;
3757 } else if (data_count + *ppdata > end_of_smb) {
3758 cFYI(1, "data %p + count %d (%p) past smb end %p start %p",
3759 *ppdata, data_count, (data_count + *ppdata),
3760 end_of_smb, pSMBr);
3761 return -EINVAL;
Jeff Layton820a8032011-05-04 08:05:26 -04003762 } else if (parm_count + data_count > bcc) {
Jeff Layton79df1ba2010-12-06 12:52:08 -05003763 cFYI(1, "parm count and data count larger than SMB");
3764 return -EINVAL;
3765 }
3766 *pdatalen = data_count;
3767 *pparmlen = parm_count;
3768 return 0;
3769}
3770
Steve French0a4b92c2006-01-12 15:44:21 -08003771/* Get Security Descriptor (by handle) from remote server for a file or dir */
3772int
Steve French96daf2b2011-05-27 04:34:02 +00003773CIFSSMBGetCIFSACL(const int xid, struct cifs_tcon *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003774 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003775{
3776 int rc = 0;
3777 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003778 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003779 struct kvec iov[1];
3780
Joe Perchesb6b38f72010-04-21 03:50:45 +00003781 cFYI(1, "GetCifsACL");
Steve French0a4b92c2006-01-12 15:44:21 -08003782
Steve French630f3f0c2007-10-25 21:17:17 +00003783 *pbuflen = 0;
3784 *acl_inf = NULL;
3785
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003786 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003787 8 /* parm len */, tcon, (void **) &pSMB);
3788 if (rc)
3789 return rc;
3790
3791 pSMB->MaxParameterCount = cpu_to_le32(4);
3792 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3793 pSMB->MaxSetupCount = 0;
3794 pSMB->Fid = fid; /* file handle always le */
3795 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3796 CIFS_ACL_DACL);
3797 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003798 inc_rfc1001_len(pSMB, 11);
Steve French0a4b92c2006-01-12 15:44:21 -08003799 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003800 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French0a4b92c2006-01-12 15:44:21 -08003801
Steve Frencha761ac52007-10-18 21:45:27 +00003802 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Jeff Layton77499812011-01-11 07:24:23 -05003803 0);
Steve French0a4b92c2006-01-12 15:44:21 -08003804 cifs_stats_inc(&tcon->num_acl_get);
3805 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003806 cFYI(1, "Send error in QuerySecDesc = %d", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08003807 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003808 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003809 __u32 parm_len;
3810 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003811 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003812 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003813
3814/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003815 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003816 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003817 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003818 goto qsec_out;
3819 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3820
Joe Perchesb6b38f72010-04-21 03:50:45 +00003821 cFYI(1, "smb %p parm %p data %p", pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08003822
3823 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3824 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003825 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003826 goto qsec_out;
3827 }
3828
3829/* BB check that data area is minimum length and as big as acl_len */
3830
Steve Frenchaf6f4612007-10-16 18:40:37 +00003831 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003832 if (acl_len != *pbuflen) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003833 cERROR(1, "acl length %d does not match %d",
3834 acl_len, *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003835 if (*pbuflen > acl_len)
3836 *pbuflen = acl_len;
3837 }
Steve French0a4b92c2006-01-12 15:44:21 -08003838
Steve French630f3f0c2007-10-25 21:17:17 +00003839 /* check if buffer is big enough for the acl
3840 header followed by the smallest SID */
3841 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3842 (*pbuflen >= 64 * 1024)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003843 cERROR(1, "bad acl length %d", *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003844 rc = -EINVAL;
3845 *pbuflen = 0;
3846 } else {
3847 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3848 if (*acl_inf == NULL) {
3849 *pbuflen = 0;
3850 rc = -ENOMEM;
3851 }
3852 memcpy(*acl_inf, pdata, *pbuflen);
3853 }
Steve French0a4b92c2006-01-12 15:44:21 -08003854 }
3855qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003856 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003857 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003858 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003859 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003860/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003861 return rc;
3862}
Steve French97837582007-12-31 07:47:21 +00003863
3864int
Steve French96daf2b2011-05-27 04:34:02 +00003865CIFSSMBSetCIFSACL(const int xid, struct cifs_tcon *tcon, __u16 fid,
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003866 struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
Steve French97837582007-12-31 07:47:21 +00003867{
3868 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3869 int rc = 0;
3870 int bytes_returned = 0;
3871 SET_SEC_DESC_REQ *pSMB = NULL;
3872 NTRANSACT_RSP *pSMBr = NULL;
3873
3874setCifsAclRetry:
3875 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB,
3876 (void **) &pSMBr);
3877 if (rc)
3878 return (rc);
3879
3880 pSMB->MaxSetupCount = 0;
3881 pSMB->Reserved = 0;
3882
3883 param_count = 8;
3884 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3885 data_count = acllen;
3886 data_offset = param_offset + param_count;
3887 byte_count = 3 /* pad */ + param_count;
3888
3889 pSMB->DataCount = cpu_to_le32(data_count);
3890 pSMB->TotalDataCount = pSMB->DataCount;
3891 pSMB->MaxParameterCount = cpu_to_le32(4);
3892 pSMB->MaxDataCount = cpu_to_le32(16384);
3893 pSMB->ParameterCount = cpu_to_le32(param_count);
3894 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3895 pSMB->TotalParameterCount = pSMB->ParameterCount;
3896 pSMB->DataOffset = cpu_to_le32(data_offset);
3897 pSMB->SetupCount = 0;
3898 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3899 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3900
3901 pSMB->Fid = fid; /* file handle always le */
3902 pSMB->Reserved2 = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003903 pSMB->AclFlags = cpu_to_le32(aclflag);
Steve French97837582007-12-31 07:47:21 +00003904
3905 if (pntsd && acllen) {
3906 memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
3907 (char *) pntsd,
3908 acllen);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003909 inc_rfc1001_len(pSMB, byte_count + data_count);
Steve French97837582007-12-31 07:47:21 +00003910 } else
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003911 inc_rfc1001_len(pSMB, byte_count);
Steve French97837582007-12-31 07:47:21 +00003912
3913 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3914 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3915
Joe Perchesb6b38f72010-04-21 03:50:45 +00003916 cFYI(1, "SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00003917 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003918 cFYI(1, "Set CIFS ACL returned %d", rc);
Steve French97837582007-12-31 07:47:21 +00003919 cifs_buf_release(pSMB);
3920
3921 if (rc == -EAGAIN)
3922 goto setCifsAclRetry;
3923
3924 return (rc);
3925}
3926
Jeff Layton79df1ba2010-12-06 12:52:08 -05003927#endif /* CONFIG_CIFS_ACL */
Steve French0a4b92c2006-01-12 15:44:21 -08003928
Steve French6b8edfe2005-08-23 20:26:03 -07003929/* Legacy Query Path Information call for lookup to old servers such
3930 as Win9x/WinME */
Steve French96daf2b2011-05-27 04:34:02 +00003931int SMBQueryInformation(const int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003932 const unsigned char *searchName,
3933 FILE_ALL_INFO *pFinfo,
3934 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003935{
Steve Frenchad7a2922008-02-07 23:25:02 +00003936 QUERY_INFORMATION_REQ *pSMB;
3937 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003938 int rc = 0;
3939 int bytes_returned;
3940 int name_len;
3941
Joe Perchesb6b38f72010-04-21 03:50:45 +00003942 cFYI(1, "In SMBQPath path %s", searchName);
Steve French6b8edfe2005-08-23 20:26:03 -07003943QInfRetry:
3944 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003945 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003946 if (rc)
3947 return rc;
3948
3949 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3950 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003951 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3952 PATH_MAX, nls_codepage, remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003953 name_len++; /* trailing null */
3954 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003955 } else {
Steve French6b8edfe2005-08-23 20:26:03 -07003956 name_len = strnlen(searchName, PATH_MAX);
3957 name_len++; /* trailing null */
3958 strncpy(pSMB->FileName, searchName, name_len);
3959 }
3960 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003961 name_len++; /* account for buffer type byte */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003962 inc_rfc1001_len(pSMB, (__u16)name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07003963 pSMB->ByteCount = cpu_to_le16(name_len);
3964
3965 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003966 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003967 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003968 cFYI(1, "Send error in QueryInfo = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00003969 } else if (pFinfo) {
Steve French1bd5bbc2006-09-28 03:35:57 +00003970 struct timespec ts;
3971 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00003972
3973 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003974 /* BB FIXME - add time zone adjustment BB */
Steve French6b8edfe2005-08-23 20:26:03 -07003975 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003976 ts.tv_nsec = 0;
3977 ts.tv_sec = time;
3978 /* decode time fields */
Al Viro733f99a2006-10-14 16:48:26 +01003979 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
Steve French1bd5bbc2006-09-28 03:35:57 +00003980 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3981 pFinfo->LastAccessTime = 0;
Steve French70ca7342005-09-22 16:32:06 -07003982 pFinfo->AllocationSize =
3983 cpu_to_le64(le32_to_cpu(pSMBr->size));
3984 pFinfo->EndOfFile = pFinfo->AllocationSize;
3985 pFinfo->Attributes =
3986 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003987 } else
3988 rc = -EIO; /* bad buffer passed in */
3989
3990 cifs_buf_release(pSMB);
3991
3992 if (rc == -EAGAIN)
3993 goto QInfRetry;
3994
3995 return rc;
3996}
3997
Jeff Laytonbcd53572010-02-12 07:44:16 -05003998int
Steve French96daf2b2011-05-27 04:34:02 +00003999CIFSSMBQFileInfo(const int xid, struct cifs_tcon *tcon,
Jeff Laytonbcd53572010-02-12 07:44:16 -05004000 u16 netfid, FILE_ALL_INFO *pFindData)
4001{
4002 struct smb_t2_qfi_req *pSMB = NULL;
4003 struct smb_t2_qfi_rsp *pSMBr = NULL;
4004 int rc = 0;
4005 int bytes_returned;
4006 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07004007
Jeff Laytonbcd53572010-02-12 07:44:16 -05004008QFileInfoRetry:
4009 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4010 (void **) &pSMBr);
4011 if (rc)
4012 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07004013
Jeff Laytonbcd53572010-02-12 07:44:16 -05004014 params = 2 /* level */ + 2 /* fid */;
4015 pSMB->t2.TotalDataCount = 0;
4016 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4017 /* BB find exact max data count below from sess structure BB */
4018 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4019 pSMB->t2.MaxSetupCount = 0;
4020 pSMB->t2.Reserved = 0;
4021 pSMB->t2.Flags = 0;
4022 pSMB->t2.Timeout = 0;
4023 pSMB->t2.Reserved2 = 0;
4024 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4025 Fid) - 4);
4026 pSMB->t2.DataCount = 0;
4027 pSMB->t2.DataOffset = 0;
4028 pSMB->t2.SetupCount = 1;
4029 pSMB->t2.Reserved3 = 0;
4030 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4031 byte_count = params + 1 /* pad */ ;
4032 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4033 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4034 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
4035 pSMB->Pad = 0;
4036 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004037 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonbcd53572010-02-12 07:44:16 -05004038
4039 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4040 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4041 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00004042 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05004043 } else { /* decode response */
4044 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4045
4046 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4047 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004048 else if (get_bcc(&pSMBr->hdr) < 40)
Jeff Laytonbcd53572010-02-12 07:44:16 -05004049 rc = -EIO; /* bad smb */
4050 else if (pFindData) {
4051 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4052 memcpy((char *) pFindData,
4053 (char *) &pSMBr->hdr.Protocol +
4054 data_offset, sizeof(FILE_ALL_INFO));
4055 } else
4056 rc = -ENOMEM;
4057 }
4058 cifs_buf_release(pSMB);
4059 if (rc == -EAGAIN)
4060 goto QFileInfoRetry;
4061
4062 return rc;
4063}
Steve French6b8edfe2005-08-23 20:26:03 -07004064
Linus Torvalds1da177e2005-04-16 15:20:36 -07004065int
Steve French96daf2b2011-05-27 04:34:02 +00004066CIFSSMBQPathInfo(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004067 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00004068 FILE_ALL_INFO *pFindData,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004069 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07004070 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004071{
4072/* level 263 SMB_QUERY_FILE_ALL_INFO */
4073 TRANSACTION2_QPI_REQ *pSMB = NULL;
4074 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4075 int rc = 0;
4076 int bytes_returned;
4077 int name_len;
4078 __u16 params, byte_count;
4079
Joe Perchesb6b38f72010-04-21 03:50:45 +00004080/* cFYI(1, "In QPathInfo path %s", searchName); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004081QPathInfoRetry:
4082 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4083 (void **) &pSMBr);
4084 if (rc)
4085 return rc;
4086
4087 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4088 name_len =
Steve French50c2f752007-07-13 00:33:32 +00004089 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07004090 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004091 name_len++; /* trailing null */
4092 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004093 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004094 name_len = strnlen(searchName, PATH_MAX);
4095 name_len++; /* trailing null */
4096 strncpy(pSMB->FileName, searchName, name_len);
4097 }
4098
Steve French50c2f752007-07-13 00:33:32 +00004099 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004100 pSMB->TotalDataCount = 0;
4101 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004102 /* BB find exact max SMB PDU from sess structure BB */
4103 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004104 pSMB->MaxSetupCount = 0;
4105 pSMB->Reserved = 0;
4106 pSMB->Flags = 0;
4107 pSMB->Timeout = 0;
4108 pSMB->Reserved2 = 0;
4109 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004110 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004111 pSMB->DataCount = 0;
4112 pSMB->DataOffset = 0;
4113 pSMB->SetupCount = 1;
4114 pSMB->Reserved3 = 0;
4115 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4116 byte_count = params + 1 /* pad */ ;
4117 pSMB->TotalParameterCount = cpu_to_le16(params);
4118 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00004119 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004120 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
4121 else
4122 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004123 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004124 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004125 pSMB->ByteCount = cpu_to_le16(byte_count);
4126
4127 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4128 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4129 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004130 cFYI(1, "Send error in QPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004131 } else { /* decode response */
4132 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4133
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004134 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4135 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004136 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004137 rc = -EIO; /* bad smb */
Jeff Layton820a8032011-05-04 08:05:26 -04004138 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
Steve French50c2f752007-07-13 00:33:32 +00004139 rc = -EIO; /* 24 or 26 expected but we do not read
4140 last field */
4141 else if (pFindData) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004142 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004143 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00004144
4145 /* On legacy responses we do not read the last field,
4146 EAsize, fortunately since it varies by subdialect and
4147 also note it differs on Set vs. Get, ie two bytes or 4
4148 bytes depending but we don't care here */
4149 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004150 size = sizeof(FILE_INFO_STANDARD);
4151 else
4152 size = sizeof(FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004153 memcpy((char *) pFindData,
4154 (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004155 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004156 } else
4157 rc = -ENOMEM;
4158 }
4159 cifs_buf_release(pSMB);
4160 if (rc == -EAGAIN)
4161 goto QPathInfoRetry;
4162
4163 return rc;
4164}
4165
4166int
Steve French96daf2b2011-05-27 04:34:02 +00004167CIFSSMBUnixQFileInfo(const int xid, struct cifs_tcon *tcon,
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004168 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
4169{
4170 struct smb_t2_qfi_req *pSMB = NULL;
4171 struct smb_t2_qfi_rsp *pSMBr = NULL;
4172 int rc = 0;
4173 int bytes_returned;
4174 __u16 params, byte_count;
4175
4176UnixQFileInfoRetry:
4177 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4178 (void **) &pSMBr);
4179 if (rc)
4180 return rc;
4181
4182 params = 2 /* level */ + 2 /* fid */;
4183 pSMB->t2.TotalDataCount = 0;
4184 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4185 /* BB find exact max data count below from sess structure BB */
4186 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4187 pSMB->t2.MaxSetupCount = 0;
4188 pSMB->t2.Reserved = 0;
4189 pSMB->t2.Flags = 0;
4190 pSMB->t2.Timeout = 0;
4191 pSMB->t2.Reserved2 = 0;
4192 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4193 Fid) - 4);
4194 pSMB->t2.DataCount = 0;
4195 pSMB->t2.DataOffset = 0;
4196 pSMB->t2.SetupCount = 1;
4197 pSMB->t2.Reserved3 = 0;
4198 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4199 byte_count = params + 1 /* pad */ ;
4200 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4201 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4202 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4203 pSMB->Pad = 0;
4204 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004205 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004206
4207 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4208 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4209 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00004210 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004211 } else { /* decode response */
4212 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4213
Jeff Layton820a8032011-05-04 08:05:26 -04004214 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Steve Frenchf19159d2010-04-21 04:12:10 +00004215 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response.\n"
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004216 "Unix Extensions can be disabled on mount "
Steve Frenchf19159d2010-04-21 04:12:10 +00004217 "by specifying the nosfu mount option.");
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004218 rc = -EIO; /* bad smb */
4219 } else {
4220 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4221 memcpy((char *) pFindData,
4222 (char *) &pSMBr->hdr.Protocol +
4223 data_offset,
4224 sizeof(FILE_UNIX_BASIC_INFO));
4225 }
4226 }
4227
4228 cifs_buf_release(pSMB);
4229 if (rc == -EAGAIN)
4230 goto UnixQFileInfoRetry;
4231
4232 return rc;
4233}
4234
4235int
Steve French96daf2b2011-05-27 04:34:02 +00004236CIFSSMBUnixQPathInfo(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004237 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00004238 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07004239 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004240{
4241/* SMB_QUERY_FILE_UNIX_BASIC */
4242 TRANSACTION2_QPI_REQ *pSMB = NULL;
4243 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4244 int rc = 0;
4245 int bytes_returned = 0;
4246 int name_len;
4247 __u16 params, byte_count;
4248
Joe Perchesb6b38f72010-04-21 03:50:45 +00004249 cFYI(1, "In QPathInfo (Unix) the path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004250UnixQPathInfoRetry:
4251 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4252 (void **) &pSMBr);
4253 if (rc)
4254 return rc;
4255
4256 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4257 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004258 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07004259 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004260 name_len++; /* trailing null */
4261 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004262 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004263 name_len = strnlen(searchName, PATH_MAX);
4264 name_len++; /* trailing null */
4265 strncpy(pSMB->FileName, searchName, name_len);
4266 }
4267
Steve French50c2f752007-07-13 00:33:32 +00004268 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004269 pSMB->TotalDataCount = 0;
4270 pSMB->MaxParameterCount = cpu_to_le16(2);
4271 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00004272 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004273 pSMB->MaxSetupCount = 0;
4274 pSMB->Reserved = 0;
4275 pSMB->Flags = 0;
4276 pSMB->Timeout = 0;
4277 pSMB->Reserved2 = 0;
4278 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004279 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004280 pSMB->DataCount = 0;
4281 pSMB->DataOffset = 0;
4282 pSMB->SetupCount = 1;
4283 pSMB->Reserved3 = 0;
4284 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4285 byte_count = params + 1 /* pad */ ;
4286 pSMB->TotalParameterCount = cpu_to_le16(params);
4287 pSMB->ParameterCount = pSMB->TotalParameterCount;
4288 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4289 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004290 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004291 pSMB->ByteCount = cpu_to_le16(byte_count);
4292
4293 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4294 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4295 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004296 cFYI(1, "Send error in QPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004297 } else { /* decode response */
4298 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4299
Jeff Layton820a8032011-05-04 08:05:26 -04004300 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004301 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response.\n"
Steve French1e71f252007-09-20 15:30:07 +00004302 "Unix Extensions can be disabled on mount "
Joe Perchesb6b38f72010-04-21 03:50:45 +00004303 "by specifying the nosfu mount option.");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004304 rc = -EIO; /* bad smb */
4305 } else {
4306 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4307 memcpy((char *) pFindData,
4308 (char *) &pSMBr->hdr.Protocol +
4309 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00004310 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004311 }
4312 }
4313 cifs_buf_release(pSMB);
4314 if (rc == -EAGAIN)
4315 goto UnixQPathInfoRetry;
4316
4317 return rc;
4318}
4319
Linus Torvalds1da177e2005-04-16 15:20:36 -07004320/* xid, tcon, searchName and codepage are input parms, rest are returned */
4321int
Steve French96daf2b2011-05-27 04:34:02 +00004322CIFSFindFirst(const int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004323 const char *searchName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004324 const struct nls_table *nls_codepage,
Steve French50c2f752007-07-13 00:33:32 +00004325 __u16 *pnetfid,
4326 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004327{
4328/* level 257 SMB_ */
4329 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
4330 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004331 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004332 int rc = 0;
4333 int bytes_returned = 0;
4334 int name_len;
4335 __u16 params, byte_count;
4336
Joe Perchesb6b38f72010-04-21 03:50:45 +00004337 cFYI(1, "In FindFirst for %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004338
4339findFirstRetry:
4340 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4341 (void **) &pSMBr);
4342 if (rc)
4343 return rc;
4344
4345 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4346 name_len =
Steve French50c2f752007-07-13 00:33:32 +00004347 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07004348 PATH_MAX, nls_codepage, remap);
4349 /* We can not add the asterik earlier in case
4350 it got remapped to 0xF03A as if it were part of the
4351 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004352 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07004353 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07004354 pSMB->FileName[name_len+1] = 0;
4355 pSMB->FileName[name_len+2] = '*';
4356 pSMB->FileName[name_len+3] = 0;
4357 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004358 pSMB->FileName[name_len] = 0; /* null terminate just in case */
4359 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07004360 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004361 } else { /* BB add check for overrun of SMB buf BB */
4362 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004363/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00004364 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004365 free buffer exit; BB */
4366 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07004367 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07004368 pSMB->FileName[name_len+1] = '*';
4369 pSMB->FileName[name_len+2] = 0;
4370 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004371 }
4372
4373 params = 12 + name_len /* includes null */ ;
4374 pSMB->TotalDataCount = 0; /* no EAs */
4375 pSMB->MaxParameterCount = cpu_to_le16(10);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004376 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004377 pSMB->MaxSetupCount = 0;
4378 pSMB->Reserved = 0;
4379 pSMB->Flags = 0;
4380 pSMB->Timeout = 0;
4381 pSMB->Reserved2 = 0;
4382 byte_count = params + 1 /* pad */ ;
4383 pSMB->TotalParameterCount = cpu_to_le16(params);
4384 pSMB->ParameterCount = pSMB->TotalParameterCount;
4385 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00004386 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
4387 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004388 pSMB->DataCount = 0;
4389 pSMB->DataOffset = 0;
4390 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
4391 pSMB->Reserved3 = 0;
4392 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
4393 pSMB->SearchAttributes =
4394 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
4395 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00004396 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
4397 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
Linus Torvalds1da177e2005-04-16 15:20:36 -07004398 CIFS_SEARCH_RETURN_RESUME);
4399 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4400
4401 /* BB what should we set StorageType to? Does it matter? BB */
4402 pSMB->SearchStorageType = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004403 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004404 pSMB->ByteCount = cpu_to_le16(byte_count);
4405
4406 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4407 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07004408 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004409
Steve French88274812006-03-09 22:21:45 +00004410 if (rc) {/* BB add logic to retry regular search if Unix search
4411 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004412 /* BB Add code to handle unsupported level rc */
Joe Perchesb6b38f72010-04-21 03:50:45 +00004413 cFYI(1, "Error in FindFirst = %d", rc);
Steve French1982c342005-08-17 12:38:22 -07004414
Steve French88274812006-03-09 22:21:45 +00004415 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004416
4417 /* BB eventually could optimize out free and realloc of buf */
4418 /* for this case */
4419 if (rc == -EAGAIN)
4420 goto findFirstRetry;
4421 } else { /* decode response */
4422 /* BB remember to free buffer if error BB */
4423 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00004424 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004425 unsigned int lnoff;
4426
Linus Torvalds1da177e2005-04-16 15:20:36 -07004427 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004428 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004429 else
Steve French4b18f2a2008-04-29 00:06:05 +00004430 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004431
4432 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004433 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00004434 psrch_inf->srch_entries_start =
4435 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004436 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004437 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
4438 le16_to_cpu(pSMBr->t2.ParameterOffset));
4439
Steve French790fe572007-07-07 19:25:05 +00004440 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004441 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004442 else
Steve French4b18f2a2008-04-29 00:06:05 +00004443 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004444
Steve French50c2f752007-07-13 00:33:32 +00004445 psrch_inf->entries_in_buffer =
4446 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00004447 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004448 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004449 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004450 if (CIFSMaxBufSize < lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004451 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00004452 psrch_inf->last_entry = NULL;
4453 return rc;
4454 }
4455
Steve French0752f152008-10-07 20:03:33 +00004456 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00004457 lnoff;
4458
Linus Torvalds1da177e2005-04-16 15:20:36 -07004459 *pnetfid = parms->SearchHandle;
4460 } else {
4461 cifs_buf_release(pSMB);
4462 }
4463 }
4464
4465 return rc;
4466}
4467
Steve French96daf2b2011-05-27 04:34:02 +00004468int CIFSFindNext(const int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004469 __u16 searchHandle, struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004470{
4471 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
4472 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004473 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004474 char *response_data;
4475 int rc = 0;
Jeff Layton9438fab2011-08-23 07:21:28 -04004476 int bytes_returned;
4477 unsigned int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004478 __u16 params, byte_count;
4479
Joe Perchesb6b38f72010-04-21 03:50:45 +00004480 cFYI(1, "In FindNext");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004481
Steve French4b18f2a2008-04-29 00:06:05 +00004482 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004483 return -ENOENT;
4484
4485 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4486 (void **) &pSMBr);
4487 if (rc)
4488 return rc;
4489
Steve French50c2f752007-07-13 00:33:32 +00004490 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004491 byte_count = 0;
4492 pSMB->TotalDataCount = 0; /* no EAs */
4493 pSMB->MaxParameterCount = cpu_to_le16(8);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004494 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004495 pSMB->MaxSetupCount = 0;
4496 pSMB->Reserved = 0;
4497 pSMB->Flags = 0;
4498 pSMB->Timeout = 0;
4499 pSMB->Reserved2 = 0;
4500 pSMB->ParameterOffset = cpu_to_le16(
4501 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
4502 pSMB->DataCount = 0;
4503 pSMB->DataOffset = 0;
4504 pSMB->SetupCount = 1;
4505 pSMB->Reserved3 = 0;
4506 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
4507 pSMB->SearchHandle = searchHandle; /* always kept as le */
4508 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00004509 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004510 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4511 pSMB->ResumeKey = psrch_inf->resume_key;
4512 pSMB->SearchFlags =
4513 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
4514
4515 name_len = psrch_inf->resume_name_len;
4516 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00004517 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004518 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
4519 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07004520 /* 14 byte parm len above enough for 2 byte null terminator */
4521 pSMB->ResumeFileName[name_len] = 0;
4522 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004523 } else {
4524 rc = -EINVAL;
4525 goto FNext2_err_exit;
4526 }
4527 byte_count = params + 1 /* pad */ ;
4528 pSMB->TotalParameterCount = cpu_to_le16(params);
4529 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004530 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004531 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004532
Linus Torvalds1da177e2005-04-16 15:20:36 -07004533 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4534 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07004535 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004536 if (rc) {
4537 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00004538 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07004539 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00004540 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004541 } else
Joe Perchesb6b38f72010-04-21 03:50:45 +00004542 cFYI(1, "FindNext returned = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004543 } else { /* decode response */
4544 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00004545
Steve French790fe572007-07-07 19:25:05 +00004546 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004547 unsigned int lnoff;
4548
Linus Torvalds1da177e2005-04-16 15:20:36 -07004549 /* BB fixme add lock for file (srch_info) struct here */
4550 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004551 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004552 else
Steve French4b18f2a2008-04-29 00:06:05 +00004553 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004554 response_data = (char *) &pSMBr->hdr.Protocol +
4555 le16_to_cpu(pSMBr->t2.ParameterOffset);
4556 parms = (T2_FNEXT_RSP_PARMS *)response_data;
4557 response_data = (char *)&pSMBr->hdr.Protocol +
4558 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00004559 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00004560 cifs_small_buf_release(
4561 psrch_inf->ntwrk_buf_start);
4562 else
4563 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004564 psrch_inf->srch_entries_start = response_data;
4565 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004566 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00004567 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004568 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004569 else
Steve French4b18f2a2008-04-29 00:06:05 +00004570 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00004571 psrch_inf->entries_in_buffer =
4572 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004573 psrch_inf->index_of_last_entry +=
4574 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004575 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004576 if (CIFSMaxBufSize < lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004577 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00004578 psrch_inf->last_entry = NULL;
4579 return rc;
4580 } else
4581 psrch_inf->last_entry =
4582 psrch_inf->srch_entries_start + lnoff;
4583
Joe Perchesb6b38f72010-04-21 03:50:45 +00004584/* cFYI(1, "fnxt2 entries in buf %d index_of_last %d",
4585 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004586
4587 /* BB fixme add unlock here */
4588 }
4589
4590 }
4591
4592 /* BB On error, should we leave previous search buf (and count and
4593 last entry fields) intact or free the previous one? */
4594
4595 /* Note: On -EAGAIN error only caller can retry on handle based calls
4596 since file handle passed in no longer valid */
4597FNext2_err_exit:
4598 if (rc != 0)
4599 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004600 return rc;
4601}
4602
4603int
Steve French96daf2b2011-05-27 04:34:02 +00004604CIFSFindClose(const int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004605 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004606{
4607 int rc = 0;
4608 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004609
Joe Perchesb6b38f72010-04-21 03:50:45 +00004610 cFYI(1, "In CIFSSMBFindClose");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004611 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
4612
4613 /* no sense returning error if session restarted
4614 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00004615 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004616 return 0;
4617 if (rc)
4618 return rc;
4619
Linus Torvalds1da177e2005-04-16 15:20:36 -07004620 pSMB->FileID = searchHandle;
4621 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00004622 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004623 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00004624 cERROR(1, "Send error in FindClose = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00004625
Steve Frencha4544342005-08-24 13:59:35 -07004626 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004627
4628 /* Since session is dead, search handle closed on server already */
4629 if (rc == -EAGAIN)
4630 rc = 0;
4631
4632 return rc;
4633}
4634
Linus Torvalds1da177e2005-04-16 15:20:36 -07004635int
Steve French96daf2b2011-05-27 04:34:02 +00004636CIFSGetSrvInodeNumber(const int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004637 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00004638 __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00004639 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004640{
4641 int rc = 0;
4642 TRANSACTION2_QPI_REQ *pSMB = NULL;
4643 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4644 int name_len, bytes_returned;
4645 __u16 params, byte_count;
4646
Joe Perchesb6b38f72010-04-21 03:50:45 +00004647 cFYI(1, "In GetSrvInodeNum for %s", searchName);
Steve French790fe572007-07-07 19:25:05 +00004648 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00004649 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004650
4651GetInodeNumberRetry:
4652 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004653 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004654 if (rc)
4655 return rc;
4656
Linus Torvalds1da177e2005-04-16 15:20:36 -07004657 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4658 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004659 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French50c2f752007-07-13 00:33:32 +00004660 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004661 name_len++; /* trailing null */
4662 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004663 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004664 name_len = strnlen(searchName, PATH_MAX);
4665 name_len++; /* trailing null */
4666 strncpy(pSMB->FileName, searchName, name_len);
4667 }
4668
4669 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4670 pSMB->TotalDataCount = 0;
4671 pSMB->MaxParameterCount = cpu_to_le16(2);
4672 /* BB find exact max data count below from sess structure BB */
4673 pSMB->MaxDataCount = cpu_to_le16(4000);
4674 pSMB->MaxSetupCount = 0;
4675 pSMB->Reserved = 0;
4676 pSMB->Flags = 0;
4677 pSMB->Timeout = 0;
4678 pSMB->Reserved2 = 0;
4679 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004680 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004681 pSMB->DataCount = 0;
4682 pSMB->DataOffset = 0;
4683 pSMB->SetupCount = 1;
4684 pSMB->Reserved3 = 0;
4685 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4686 byte_count = params + 1 /* pad */ ;
4687 pSMB->TotalParameterCount = cpu_to_le16(params);
4688 pSMB->ParameterCount = pSMB->TotalParameterCount;
4689 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4690 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004691 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004692 pSMB->ByteCount = cpu_to_le16(byte_count);
4693
4694 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4695 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4696 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004697 cFYI(1, "error %d in QueryInternalInfo", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004698 } else {
4699 /* decode response */
4700 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004701 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04004702 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004703 /* If rc should we check for EOPNOSUPP and
4704 disable the srvino flag? or in caller? */
4705 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00004706 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004707 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4708 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00004709 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004710 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00004711 if (count < 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004712 cFYI(1, "Illegal size ret in QryIntrnlInf");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004713 rc = -EIO;
4714 goto GetInodeNumOut;
4715 }
4716 pfinfo = (struct file_internal_info *)
4717 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00004718 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004719 }
4720 }
4721GetInodeNumOut:
4722 cifs_buf_release(pSMB);
4723 if (rc == -EAGAIN)
4724 goto GetInodeNumberRetry;
4725 return rc;
4726}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004727
Igor Mammedovfec45852008-05-16 13:06:30 +04004728/* parses DFS refferal V3 structure
4729 * caller is responsible for freeing target_nodes
4730 * returns:
4731 * on success - 0
4732 * on failure - errno
4733 */
4734static int
Steve Frencha1fe78f2008-05-16 18:48:38 +00004735parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
Igor Mammedovfec45852008-05-16 13:06:30 +04004736 unsigned int *num_of_nodes,
4737 struct dfs_info3_param **target_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004738 const struct nls_table *nls_codepage, int remap,
4739 const char *searchName)
Igor Mammedovfec45852008-05-16 13:06:30 +04004740{
4741 int i, rc = 0;
4742 char *data_end;
4743 bool is_unicode;
4744 struct dfs_referral_level_3 *ref;
4745
Harvey Harrison5ca33c62008-07-23 17:45:58 -07004746 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4747 is_unicode = true;
4748 else
4749 is_unicode = false;
Igor Mammedovfec45852008-05-16 13:06:30 +04004750 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
4751
4752 if (*num_of_nodes < 1) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004753 cERROR(1, "num_referrals: must be at least > 0,"
4754 "but we get num_referrals = %d\n", *num_of_nodes);
Igor Mammedovfec45852008-05-16 13:06:30 +04004755 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004756 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004757 }
4758
4759 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
Al Viro1d92cfd2008-06-02 10:59:02 +01004760 if (ref->VersionNumber != cpu_to_le16(3)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004761 cERROR(1, "Referrals of V%d version are not supported,"
4762 "should be V3", le16_to_cpu(ref->VersionNumber));
Igor Mammedovfec45852008-05-16 13:06:30 +04004763 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004764 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004765 }
4766
4767 /* get the upper boundary of the resp buffer */
4768 data_end = (char *)(&(pSMBr->PathConsumed)) +
4769 le16_to_cpu(pSMBr->t2.DataCount);
4770
Steve Frenchf19159d2010-04-21 04:12:10 +00004771 cFYI(1, "num_referrals: %d dfs flags: 0x%x ...\n",
Igor Mammedovfec45852008-05-16 13:06:30 +04004772 *num_of_nodes,
Joe Perchesb6b38f72010-04-21 03:50:45 +00004773 le32_to_cpu(pSMBr->DFSFlags));
Igor Mammedovfec45852008-05-16 13:06:30 +04004774
4775 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
4776 *num_of_nodes, GFP_KERNEL);
4777 if (*target_nodes == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004778 cERROR(1, "Failed to allocate buffer for target_nodes\n");
Igor Mammedovfec45852008-05-16 13:06:30 +04004779 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004780 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004781 }
4782
Daniel Mack3ad2f3f2010-02-03 08:01:28 +08004783 /* collect necessary data from referrals */
Igor Mammedovfec45852008-05-16 13:06:30 +04004784 for (i = 0; i < *num_of_nodes; i++) {
4785 char *temp;
4786 int max_len;
4787 struct dfs_info3_param *node = (*target_nodes)+i;
4788
Steve French0e0d2cf2009-05-01 05:27:32 +00004789 node->flags = le32_to_cpu(pSMBr->DFSFlags);
Igor Mammedov2c556082008-10-23 13:58:42 +04004790 if (is_unicode) {
Jeff Layton331c3132008-12-17 06:31:53 -05004791 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4792 GFP_KERNEL);
Steve French2920ee22009-08-31 15:27:26 +00004793 if (tmp == NULL) {
4794 rc = -ENOMEM;
4795 goto parse_DFS_referrals_exit;
4796 }
Igor Mammedov2c556082008-10-23 13:58:42 +04004797 cifsConvertToUCS((__le16 *) tmp, searchName,
4798 PATH_MAX, nls_codepage, remap);
Jeff Layton69f801f2009-04-30 06:46:32 -04004799 node->path_consumed = cifs_ucs2_bytes(tmp,
4800 le16_to_cpu(pSMBr->PathConsumed),
Igor Mammedov2c556082008-10-23 13:58:42 +04004801 nls_codepage);
4802 kfree(tmp);
4803 } else
4804 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4805
Igor Mammedovfec45852008-05-16 13:06:30 +04004806 node->server_type = le16_to_cpu(ref->ServerType);
4807 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4808
4809 /* copy DfsPath */
4810 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4811 max_len = data_end - temp;
Steve Frenchd185cda2009-04-30 17:45:10 +00004812 node->path_name = cifs_strndup_from_ucs(temp, max_len,
4813 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004814 if (!node->path_name) {
4815 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004816 goto parse_DFS_referrals_exit;
Jeff Layton066ce682009-04-30 07:16:14 -04004817 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004818
4819 /* copy link target UNC */
4820 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4821 max_len = data_end - temp;
Steve Frenchd185cda2009-04-30 17:45:10 +00004822 node->node_name = cifs_strndup_from_ucs(temp, max_len,
4823 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004824 if (!node->node_name)
4825 rc = -ENOMEM;
Igor Mammedovfec45852008-05-16 13:06:30 +04004826 }
4827
Steve Frencha1fe78f2008-05-16 18:48:38 +00004828parse_DFS_referrals_exit:
Igor Mammedovfec45852008-05-16 13:06:30 +04004829 if (rc) {
4830 free_dfs_info_array(*target_nodes, *num_of_nodes);
4831 *target_nodes = NULL;
4832 *num_of_nodes = 0;
4833 }
4834 return rc;
4835}
4836
Linus Torvalds1da177e2005-04-16 15:20:36 -07004837int
Steve French96daf2b2011-05-27 04:34:02 +00004838CIFSGetDFSRefer(const int xid, struct cifs_ses *ses,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004839 const unsigned char *searchName,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004840 struct dfs_info3_param **target_nodes,
4841 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004842 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004843{
4844/* TRANS2_GET_DFS_REFERRAL */
4845 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4846 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004847 int rc = 0;
4848 int bytes_returned;
4849 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004850 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004851 *num_of_nodes = 0;
4852 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004853
Joe Perchesb6b38f72010-04-21 03:50:45 +00004854 cFYI(1, "In GetDFSRefer the path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004855 if (ses == NULL)
4856 return -ENODEV;
4857getDFSRetry:
4858 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4859 (void **) &pSMBr);
4860 if (rc)
4861 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004862
4863 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004864 but should never be null here anyway */
4865 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004866 pSMB->hdr.Tid = ses->ipc_tid;
4867 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004868 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004869 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004870 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004871 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004872
4873 if (ses->capabilities & CAP_UNICODE) {
4874 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4875 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004876 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07004877 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004878 name_len++; /* trailing null */
4879 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004880 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004881 name_len = strnlen(searchName, PATH_MAX);
4882 name_len++; /* trailing null */
4883 strncpy(pSMB->RequestFileName, searchName, name_len);
4884 }
4885
Steve French790fe572007-07-07 19:25:05 +00004886 if (ses->server) {
Steve French96daf2b2011-05-27 04:34:02 +00004887 if (ses->server->sec_mode &
Steve French1a4e15a2006-10-12 21:33:51 +00004888 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4889 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4890 }
4891
Steve French50c2f752007-07-13 00:33:32 +00004892 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004893
Linus Torvalds1da177e2005-04-16 15:20:36 -07004894 params = 2 /* level */ + name_len /*includes null */ ;
4895 pSMB->TotalDataCount = 0;
4896 pSMB->DataCount = 0;
4897 pSMB->DataOffset = 0;
4898 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004899 /* BB find exact max SMB PDU from sess structure BB */
4900 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004901 pSMB->MaxSetupCount = 0;
4902 pSMB->Reserved = 0;
4903 pSMB->Flags = 0;
4904 pSMB->Timeout = 0;
4905 pSMB->Reserved2 = 0;
4906 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004907 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004908 pSMB->SetupCount = 1;
4909 pSMB->Reserved3 = 0;
4910 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4911 byte_count = params + 3 /* pad */ ;
4912 pSMB->ParameterCount = cpu_to_le16(params);
4913 pSMB->TotalParameterCount = pSMB->ParameterCount;
4914 pSMB->MaxReferralLevel = cpu_to_le16(3);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004915 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004916 pSMB->ByteCount = cpu_to_le16(byte_count);
4917
4918 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4919 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4920 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004921 cFYI(1, "Send error in GetDFSRefer = %d", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004922 goto GetDFSRefExit;
4923 }
4924 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004925
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004926 /* BB Also check if enough total bytes returned? */
Jeff Layton820a8032011-05-04 08:05:26 -04004927 if (rc || get_bcc(&pSMBr->hdr) < 17) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004928 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004929 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004930 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004931
Joe Perchesb6b38f72010-04-21 03:50:45 +00004932 cFYI(1, "Decoding GetDFSRefer response BCC: %d Offset %d",
Jeff Layton820a8032011-05-04 08:05:26 -04004933 get_bcc(&pSMBr->hdr),
Joe Perchesb6b38f72010-04-21 03:50:45 +00004934 le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04004935
4936 /* parse returned result into more usable form */
Steve Frencha1fe78f2008-05-16 18:48:38 +00004937 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004938 target_nodes, nls_codepage, remap,
4939 searchName);
Igor Mammedovfec45852008-05-16 13:06:30 +04004940
Linus Torvalds1da177e2005-04-16 15:20:36 -07004941GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004942 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004943
4944 if (rc == -EAGAIN)
4945 goto getDFSRetry;
4946
4947 return rc;
4948}
4949
Steve French20962432005-09-21 22:05:57 -07004950/* Query File System Info such as free space to old servers such as Win 9x */
4951int
Steve French96daf2b2011-05-27 04:34:02 +00004952SMBOldQFSInfo(const int xid, struct cifs_tcon *tcon, struct kstatfs *FSData)
Steve French20962432005-09-21 22:05:57 -07004953{
4954/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4955 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4956 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4957 FILE_SYSTEM_ALLOC_INFO *response_data;
4958 int rc = 0;
4959 int bytes_returned = 0;
4960 __u16 params, byte_count;
4961
Joe Perchesb6b38f72010-04-21 03:50:45 +00004962 cFYI(1, "OldQFSInfo");
Steve French20962432005-09-21 22:05:57 -07004963oldQFSInfoRetry:
4964 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4965 (void **) &pSMBr);
4966 if (rc)
4967 return rc;
Steve French20962432005-09-21 22:05:57 -07004968
4969 params = 2; /* level */
4970 pSMB->TotalDataCount = 0;
4971 pSMB->MaxParameterCount = cpu_to_le16(2);
4972 pSMB->MaxDataCount = cpu_to_le16(1000);
4973 pSMB->MaxSetupCount = 0;
4974 pSMB->Reserved = 0;
4975 pSMB->Flags = 0;
4976 pSMB->Timeout = 0;
4977 pSMB->Reserved2 = 0;
4978 byte_count = params + 1 /* pad */ ;
4979 pSMB->TotalParameterCount = cpu_to_le16(params);
4980 pSMB->ParameterCount = pSMB->TotalParameterCount;
4981 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4982 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4983 pSMB->DataCount = 0;
4984 pSMB->DataOffset = 0;
4985 pSMB->SetupCount = 1;
4986 pSMB->Reserved3 = 0;
4987 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4988 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004989 inc_rfc1001_len(pSMB, byte_count);
Steve French20962432005-09-21 22:05:57 -07004990 pSMB->ByteCount = cpu_to_le16(byte_count);
4991
4992 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4993 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4994 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004995 cFYI(1, "Send error in QFSInfo = %d", rc);
Steve French20962432005-09-21 22:05:57 -07004996 } else { /* decode response */
4997 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4998
Jeff Layton820a8032011-05-04 08:05:26 -04004999 if (rc || get_bcc(&pSMBr->hdr) < 18)
Steve French20962432005-09-21 22:05:57 -07005000 rc = -EIO; /* bad smb */
5001 else {
5002 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesb6b38f72010-04-21 03:50:45 +00005003 cFYI(1, "qfsinf resp BCC: %d Offset %d",
Jeff Layton820a8032011-05-04 08:05:26 -04005004 get_bcc(&pSMBr->hdr), data_offset);
Steve French20962432005-09-21 22:05:57 -07005005
Steve French50c2f752007-07-13 00:33:32 +00005006 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07005007 (((char *) &pSMBr->hdr.Protocol) + data_offset);
5008 FSData->f_bsize =
5009 le16_to_cpu(response_data->BytesPerSector) *
5010 le32_to_cpu(response_data->
5011 SectorsPerAllocationUnit);
5012 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00005013 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07005014 FSData->f_bfree = FSData->f_bavail =
5015 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesb6b38f72010-04-21 03:50:45 +00005016 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
5017 (unsigned long long)FSData->f_blocks,
5018 (unsigned long long)FSData->f_bfree,
5019 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07005020 }
5021 }
5022 cifs_buf_release(pSMB);
5023
5024 if (rc == -EAGAIN)
5025 goto oldQFSInfoRetry;
5026
5027 return rc;
5028}
5029
Linus Torvalds1da177e2005-04-16 15:20:36 -07005030int
Steve French96daf2b2011-05-27 04:34:02 +00005031CIFSSMBQFSInfo(const int xid, struct cifs_tcon *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005032{
5033/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
5034 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5035 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5036 FILE_SYSTEM_INFO *response_data;
5037 int rc = 0;
5038 int bytes_returned = 0;
5039 __u16 params, byte_count;
5040
Joe Perchesb6b38f72010-04-21 03:50:45 +00005041 cFYI(1, "In QFSInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005042QFSInfoRetry:
5043 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5044 (void **) &pSMBr);
5045 if (rc)
5046 return rc;
5047
5048 params = 2; /* level */
5049 pSMB->TotalDataCount = 0;
5050 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07005051 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005052 pSMB->MaxSetupCount = 0;
5053 pSMB->Reserved = 0;
5054 pSMB->Flags = 0;
5055 pSMB->Timeout = 0;
5056 pSMB->Reserved2 = 0;
5057 byte_count = params + 1 /* pad */ ;
5058 pSMB->TotalParameterCount = cpu_to_le16(params);
5059 pSMB->ParameterCount = pSMB->TotalParameterCount;
5060 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005061 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005062 pSMB->DataCount = 0;
5063 pSMB->DataOffset = 0;
5064 pSMB->SetupCount = 1;
5065 pSMB->Reserved3 = 0;
5066 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5067 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005068 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005069 pSMB->ByteCount = cpu_to_le16(byte_count);
5070
5071 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5072 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5073 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005074 cFYI(1, "Send error in QFSInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005075 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00005076 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005077
Jeff Layton820a8032011-05-04 08:05:26 -04005078 if (rc || get_bcc(&pSMBr->hdr) < 24)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005079 rc = -EIO; /* bad smb */
5080 else {
5081 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005082
5083 response_data =
5084 (FILE_SYSTEM_INFO
5085 *) (((char *) &pSMBr->hdr.Protocol) +
5086 data_offset);
5087 FSData->f_bsize =
5088 le32_to_cpu(response_data->BytesPerSector) *
5089 le32_to_cpu(response_data->
5090 SectorsPerAllocationUnit);
5091 FSData->f_blocks =
5092 le64_to_cpu(response_data->TotalAllocationUnits);
5093 FSData->f_bfree = FSData->f_bavail =
5094 le64_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesb6b38f72010-04-21 03:50:45 +00005095 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
5096 (unsigned long long)FSData->f_blocks,
5097 (unsigned long long)FSData->f_bfree,
5098 FSData->f_bsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005099 }
5100 }
5101 cifs_buf_release(pSMB);
5102
5103 if (rc == -EAGAIN)
5104 goto QFSInfoRetry;
5105
5106 return rc;
5107}
5108
5109int
Steve French96daf2b2011-05-27 04:34:02 +00005110CIFSSMBQFSAttributeInfo(const int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005111{
5112/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
5113 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5114 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5115 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
5116 int rc = 0;
5117 int bytes_returned = 0;
5118 __u16 params, byte_count;
5119
Joe Perchesb6b38f72010-04-21 03:50:45 +00005120 cFYI(1, "In QFSAttributeInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005121QFSAttributeRetry:
5122 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5123 (void **) &pSMBr);
5124 if (rc)
5125 return rc;
5126
5127 params = 2; /* level */
5128 pSMB->TotalDataCount = 0;
5129 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005130 /* BB find exact max SMB PDU from sess structure BB */
5131 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005132 pSMB->MaxSetupCount = 0;
5133 pSMB->Reserved = 0;
5134 pSMB->Flags = 0;
5135 pSMB->Timeout = 0;
5136 pSMB->Reserved2 = 0;
5137 byte_count = params + 1 /* pad */ ;
5138 pSMB->TotalParameterCount = cpu_to_le16(params);
5139 pSMB->ParameterCount = pSMB->TotalParameterCount;
5140 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005141 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005142 pSMB->DataCount = 0;
5143 pSMB->DataOffset = 0;
5144 pSMB->SetupCount = 1;
5145 pSMB->Reserved3 = 0;
5146 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5147 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005148 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005149 pSMB->ByteCount = cpu_to_le16(byte_count);
5150
5151 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5152 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5153 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005154 cERROR(1, "Send error in QFSAttributeInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005155 } else { /* decode response */
5156 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5157
Jeff Layton820a8032011-05-04 08:05:26 -04005158 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Steve French50c2f752007-07-13 00:33:32 +00005159 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005160 rc = -EIO; /* bad smb */
5161 } else {
5162 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5163 response_data =
5164 (FILE_SYSTEM_ATTRIBUTE_INFO
5165 *) (((char *) &pSMBr->hdr.Protocol) +
5166 data_offset);
5167 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005168 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005169 }
5170 }
5171 cifs_buf_release(pSMB);
5172
5173 if (rc == -EAGAIN)
5174 goto QFSAttributeRetry;
5175
5176 return rc;
5177}
5178
5179int
Steve French96daf2b2011-05-27 04:34:02 +00005180CIFSSMBQFSDeviceInfo(const int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005181{
5182/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
5183 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5184 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5185 FILE_SYSTEM_DEVICE_INFO *response_data;
5186 int rc = 0;
5187 int bytes_returned = 0;
5188 __u16 params, byte_count;
5189
Joe Perchesb6b38f72010-04-21 03:50:45 +00005190 cFYI(1, "In QFSDeviceInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005191QFSDeviceRetry:
5192 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5193 (void **) &pSMBr);
5194 if (rc)
5195 return rc;
5196
5197 params = 2; /* level */
5198 pSMB->TotalDataCount = 0;
5199 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005200 /* BB find exact max SMB PDU from sess structure BB */
5201 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005202 pSMB->MaxSetupCount = 0;
5203 pSMB->Reserved = 0;
5204 pSMB->Flags = 0;
5205 pSMB->Timeout = 0;
5206 pSMB->Reserved2 = 0;
5207 byte_count = params + 1 /* pad */ ;
5208 pSMB->TotalParameterCount = cpu_to_le16(params);
5209 pSMB->ParameterCount = pSMB->TotalParameterCount;
5210 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005211 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005212
5213 pSMB->DataCount = 0;
5214 pSMB->DataOffset = 0;
5215 pSMB->SetupCount = 1;
5216 pSMB->Reserved3 = 0;
5217 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5218 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005219 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005220 pSMB->ByteCount = cpu_to_le16(byte_count);
5221
5222 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5223 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5224 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005225 cFYI(1, "Send error in QFSDeviceInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005226 } else { /* decode response */
5227 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5228
Jeff Layton820a8032011-05-04 08:05:26 -04005229 if (rc || get_bcc(&pSMBr->hdr) <
5230 sizeof(FILE_SYSTEM_DEVICE_INFO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005231 rc = -EIO; /* bad smb */
5232 else {
5233 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5234 response_data =
Steve French737b7582005-04-28 22:41:06 -07005235 (FILE_SYSTEM_DEVICE_INFO *)
5236 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07005237 data_offset);
5238 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005239 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005240 }
5241 }
5242 cifs_buf_release(pSMB);
5243
5244 if (rc == -EAGAIN)
5245 goto QFSDeviceRetry;
5246
5247 return rc;
5248}
5249
5250int
Steve French96daf2b2011-05-27 04:34:02 +00005251CIFSSMBQFSUnixInfo(const int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005252{
5253/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
5254 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5255 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5256 FILE_SYSTEM_UNIX_INFO *response_data;
5257 int rc = 0;
5258 int bytes_returned = 0;
5259 __u16 params, byte_count;
5260
Joe Perchesb6b38f72010-04-21 03:50:45 +00005261 cFYI(1, "In QFSUnixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005262QFSUnixRetry:
Jeff Laytonf5695992010-09-29 15:27:08 -04005263 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5264 (void **) &pSMB, (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005265 if (rc)
5266 return rc;
5267
5268 params = 2; /* level */
5269 pSMB->TotalDataCount = 0;
5270 pSMB->DataCount = 0;
5271 pSMB->DataOffset = 0;
5272 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005273 /* BB find exact max SMB PDU from sess structure BB */
5274 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005275 pSMB->MaxSetupCount = 0;
5276 pSMB->Reserved = 0;
5277 pSMB->Flags = 0;
5278 pSMB->Timeout = 0;
5279 pSMB->Reserved2 = 0;
5280 byte_count = params + 1 /* pad */ ;
5281 pSMB->ParameterCount = cpu_to_le16(params);
5282 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005283 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5284 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005285 pSMB->SetupCount = 1;
5286 pSMB->Reserved3 = 0;
5287 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5288 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005289 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005290 pSMB->ByteCount = cpu_to_le16(byte_count);
5291
5292 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5293 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5294 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005295 cERROR(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005296 } else { /* decode response */
5297 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5298
Jeff Layton820a8032011-05-04 08:05:26 -04005299 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005300 rc = -EIO; /* bad smb */
5301 } else {
5302 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5303 response_data =
5304 (FILE_SYSTEM_UNIX_INFO
5305 *) (((char *) &pSMBr->hdr.Protocol) +
5306 data_offset);
5307 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005308 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005309 }
5310 }
5311 cifs_buf_release(pSMB);
5312
5313 if (rc == -EAGAIN)
5314 goto QFSUnixRetry;
5315
5316
5317 return rc;
5318}
5319
Jeremy Allisonac670552005-06-22 17:26:35 -07005320int
Steve French96daf2b2011-05-27 04:34:02 +00005321CIFSSMBSetFSUnixInfo(const int xid, struct cifs_tcon *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07005322{
5323/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
5324 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
5325 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
5326 int rc = 0;
5327 int bytes_returned = 0;
5328 __u16 params, param_offset, offset, byte_count;
5329
Joe Perchesb6b38f72010-04-21 03:50:45 +00005330 cFYI(1, "In SETFSUnixInfo");
Jeremy Allisonac670552005-06-22 17:26:35 -07005331SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00005332 /* BB switch to small buf init to save memory */
Jeff Laytonf5695992010-09-29 15:27:08 -04005333 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5334 (void **) &pSMB, (void **) &pSMBr);
Jeremy Allisonac670552005-06-22 17:26:35 -07005335 if (rc)
5336 return rc;
5337
5338 params = 4; /* 2 bytes zero followed by info level. */
5339 pSMB->MaxSetupCount = 0;
5340 pSMB->Reserved = 0;
5341 pSMB->Flags = 0;
5342 pSMB->Timeout = 0;
5343 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00005344 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
5345 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07005346 offset = param_offset + params;
5347
5348 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00005349 /* BB find exact max SMB PDU from sess structure BB */
5350 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07005351 pSMB->SetupCount = 1;
5352 pSMB->Reserved3 = 0;
5353 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
5354 byte_count = 1 /* pad */ + params + 12;
5355
5356 pSMB->DataCount = cpu_to_le16(12);
5357 pSMB->ParameterCount = cpu_to_le16(params);
5358 pSMB->TotalDataCount = pSMB->DataCount;
5359 pSMB->TotalParameterCount = pSMB->ParameterCount;
5360 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5361 pSMB->DataOffset = cpu_to_le16(offset);
5362
5363 /* Params. */
5364 pSMB->FileNum = 0;
5365 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
5366
5367 /* Data. */
5368 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
5369 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
5370 pSMB->ClientUnixCap = cpu_to_le64(cap);
5371
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005372 inc_rfc1001_len(pSMB, byte_count);
Jeremy Allisonac670552005-06-22 17:26:35 -07005373 pSMB->ByteCount = cpu_to_le16(byte_count);
5374
5375 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5376 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5377 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005378 cERROR(1, "Send error in SETFSUnixInfo = %d", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07005379 } else { /* decode response */
5380 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00005381 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07005382 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07005383 }
5384 cifs_buf_release(pSMB);
5385
5386 if (rc == -EAGAIN)
5387 goto SETFSUnixRetry;
5388
5389 return rc;
5390}
5391
5392
Linus Torvalds1da177e2005-04-16 15:20:36 -07005393
5394int
Steve French96daf2b2011-05-27 04:34:02 +00005395CIFSSMBQFSPosixInfo(const int xid, struct cifs_tcon *tcon,
Steve French737b7582005-04-28 22:41:06 -07005396 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005397{
5398/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
5399 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5400 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5401 FILE_SYSTEM_POSIX_INFO *response_data;
5402 int rc = 0;
5403 int bytes_returned = 0;
5404 __u16 params, byte_count;
5405
Joe Perchesb6b38f72010-04-21 03:50:45 +00005406 cFYI(1, "In QFSPosixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005407QFSPosixRetry:
5408 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5409 (void **) &pSMBr);
5410 if (rc)
5411 return rc;
5412
5413 params = 2; /* level */
5414 pSMB->TotalDataCount = 0;
5415 pSMB->DataCount = 0;
5416 pSMB->DataOffset = 0;
5417 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005418 /* BB find exact max SMB PDU from sess structure BB */
5419 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005420 pSMB->MaxSetupCount = 0;
5421 pSMB->Reserved = 0;
5422 pSMB->Flags = 0;
5423 pSMB->Timeout = 0;
5424 pSMB->Reserved2 = 0;
5425 byte_count = params + 1 /* pad */ ;
5426 pSMB->ParameterCount = cpu_to_le16(params);
5427 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005428 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5429 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005430 pSMB->SetupCount = 1;
5431 pSMB->Reserved3 = 0;
5432 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5433 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005434 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005435 pSMB->ByteCount = cpu_to_le16(byte_count);
5436
5437 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5438 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5439 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005440 cFYI(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005441 } else { /* decode response */
5442 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5443
Jeff Layton820a8032011-05-04 08:05:26 -04005444 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005445 rc = -EIO; /* bad smb */
5446 } else {
5447 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5448 response_data =
5449 (FILE_SYSTEM_POSIX_INFO
5450 *) (((char *) &pSMBr->hdr.Protocol) +
5451 data_offset);
5452 FSData->f_bsize =
5453 le32_to_cpu(response_data->BlockSize);
5454 FSData->f_blocks =
5455 le64_to_cpu(response_data->TotalBlocks);
5456 FSData->f_bfree =
5457 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00005458 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005459 FSData->f_bavail = FSData->f_bfree;
5460 } else {
5461 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00005462 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005463 }
Steve French790fe572007-07-07 19:25:05 +00005464 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005465 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00005466 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00005467 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005468 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00005469 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005470 }
5471 }
5472 cifs_buf_release(pSMB);
5473
5474 if (rc == -EAGAIN)
5475 goto QFSPosixRetry;
5476
5477 return rc;
5478}
5479
5480
Steve French50c2f752007-07-13 00:33:32 +00005481/* We can not use write of zero bytes trick to
5482 set file size due to need for large file support. Also note that
5483 this SetPathInfo is preferred to SetFileInfo based method in next
Linus Torvalds1da177e2005-04-16 15:20:36 -07005484 routine which is only needed to work around a sharing violation bug
5485 in Samba which this routine can run into */
5486
5487int
Steve French96daf2b2011-05-27 04:34:02 +00005488CIFSSMBSetEOF(const int xid, struct cifs_tcon *tcon, const char *fileName,
Steve French4b18f2a2008-04-29 00:06:05 +00005489 __u64 size, bool SetAllocation,
Steve French737b7582005-04-28 22:41:06 -07005490 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005491{
5492 struct smb_com_transaction2_spi_req *pSMB = NULL;
5493 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5494 struct file_end_of_file_info *parm_data;
5495 int name_len;
5496 int rc = 0;
5497 int bytes_returned = 0;
5498 __u16 params, byte_count, data_count, param_offset, offset;
5499
Joe Perchesb6b38f72010-04-21 03:50:45 +00005500 cFYI(1, "In SetEOF");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005501SetEOFRetry:
5502 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5503 (void **) &pSMBr);
5504 if (rc)
5505 return rc;
5506
5507 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5508 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05005509 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005510 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005511 name_len++; /* trailing null */
5512 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005513 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005514 name_len = strnlen(fileName, PATH_MAX);
5515 name_len++; /* trailing null */
5516 strncpy(pSMB->FileName, fileName, name_len);
5517 }
5518 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005519 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005520 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07005521 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005522 pSMB->MaxSetupCount = 0;
5523 pSMB->Reserved = 0;
5524 pSMB->Flags = 0;
5525 pSMB->Timeout = 0;
5526 pSMB->Reserved2 = 0;
5527 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005528 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005529 offset = param_offset + params;
Steve French790fe572007-07-07 19:25:05 +00005530 if (SetAllocation) {
Steve French50c2f752007-07-13 00:33:32 +00005531 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5532 pSMB->InformationLevel =
5533 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5534 else
5535 pSMB->InformationLevel =
5536 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5537 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005538 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5539 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005540 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005541 else
5542 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005543 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005544 }
5545
5546 parm_data =
5547 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
5548 offset);
5549 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5550 pSMB->DataOffset = cpu_to_le16(offset);
5551 pSMB->SetupCount = 1;
5552 pSMB->Reserved3 = 0;
5553 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5554 byte_count = 3 /* pad */ + params + data_count;
5555 pSMB->DataCount = cpu_to_le16(data_count);
5556 pSMB->TotalDataCount = pSMB->DataCount;
5557 pSMB->ParameterCount = cpu_to_le16(params);
5558 pSMB->TotalParameterCount = pSMB->ParameterCount;
5559 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005560 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005561 parm_data->FileSize = cpu_to_le64(size);
5562 pSMB->ByteCount = cpu_to_le16(byte_count);
5563 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5564 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005565 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005566 cFYI(1, "SetPathInfo (file size) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005567
5568 cifs_buf_release(pSMB);
5569
5570 if (rc == -EAGAIN)
5571 goto SetEOFRetry;
5572
5573 return rc;
5574}
5575
5576int
Steve French96daf2b2011-05-27 04:34:02 +00005577CIFSSMBSetFileSize(const int xid, struct cifs_tcon *tcon, __u64 size,
Steve French4b18f2a2008-04-29 00:06:05 +00005578 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005579{
5580 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005581 struct file_end_of_file_info *parm_data;
5582 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005583 __u16 params, param_offset, offset, byte_count, count;
5584
Joe Perchesb6b38f72010-04-21 03:50:45 +00005585 cFYI(1, "SetFileSize (via SetFileInfo) %lld",
5586 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07005587 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5588
Linus Torvalds1da177e2005-04-16 15:20:36 -07005589 if (rc)
5590 return rc;
5591
5592 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5593 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005594
Linus Torvalds1da177e2005-04-16 15:20:36 -07005595 params = 6;
5596 pSMB->MaxSetupCount = 0;
5597 pSMB->Reserved = 0;
5598 pSMB->Flags = 0;
5599 pSMB->Timeout = 0;
5600 pSMB->Reserved2 = 0;
5601 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5602 offset = param_offset + params;
5603
Linus Torvalds1da177e2005-04-16 15:20:36 -07005604 count = sizeof(struct file_end_of_file_info);
5605 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005606 /* BB find exact max SMB PDU from sess structure BB */
5607 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005608 pSMB->SetupCount = 1;
5609 pSMB->Reserved3 = 0;
5610 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5611 byte_count = 3 /* pad */ + params + count;
5612 pSMB->DataCount = cpu_to_le16(count);
5613 pSMB->ParameterCount = cpu_to_le16(params);
5614 pSMB->TotalDataCount = pSMB->DataCount;
5615 pSMB->TotalParameterCount = pSMB->ParameterCount;
5616 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5617 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00005618 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
5619 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005620 pSMB->DataOffset = cpu_to_le16(offset);
5621 parm_data->FileSize = cpu_to_le64(size);
5622 pSMB->Fid = fid;
Steve French790fe572007-07-07 19:25:05 +00005623 if (SetAllocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005624 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5625 pSMB->InformationLevel =
5626 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5627 else
5628 pSMB->InformationLevel =
5629 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00005630 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005631 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5632 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005633 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005634 else
5635 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005636 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005637 }
5638 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005639 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005640 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French133672e2007-11-13 22:41:37 +00005641 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005642 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005643 cFYI(1, "Send error in SetFileInfo (SetFileSize) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005644 }
5645
Steve French50c2f752007-07-13 00:33:32 +00005646 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005647 since file handle passed in no longer valid */
5648
5649 return rc;
5650}
5651
Steve French50c2f752007-07-13 00:33:32 +00005652/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07005653 an open handle, rather than by pathname - this is awkward due to
5654 potential access conflicts on the open, but it is unavoidable for these
5655 old servers since the only other choice is to go from 100 nanosecond DCE
5656 time and resort to the original setpathinfo level which takes the ancient
5657 DOS time format with 2 second granularity */
5658int
Steve French96daf2b2011-05-27 04:34:02 +00005659CIFSSMBSetFileInfo(const int xid, struct cifs_tcon *tcon,
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005660 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005661{
5662 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005663 char *data_offset;
5664 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005665 __u16 params, param_offset, offset, byte_count, count;
5666
Joe Perchesb6b38f72010-04-21 03:50:45 +00005667 cFYI(1, "Set Times (via SetFileInfo)");
Steve Frenchcd634992005-04-28 22:41:10 -07005668 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5669
Linus Torvalds1da177e2005-04-16 15:20:36 -07005670 if (rc)
5671 return rc;
5672
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005673 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5674 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005675
Linus Torvalds1da177e2005-04-16 15:20:36 -07005676 params = 6;
5677 pSMB->MaxSetupCount = 0;
5678 pSMB->Reserved = 0;
5679 pSMB->Flags = 0;
5680 pSMB->Timeout = 0;
5681 pSMB->Reserved2 = 0;
5682 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5683 offset = param_offset + params;
5684
Steve French50c2f752007-07-13 00:33:32 +00005685 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005686
Steve French26f57362007-08-30 22:09:15 +00005687 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005688 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005689 /* BB find max SMB PDU from sess */
5690 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005691 pSMB->SetupCount = 1;
5692 pSMB->Reserved3 = 0;
5693 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5694 byte_count = 3 /* pad */ + params + count;
5695 pSMB->DataCount = cpu_to_le16(count);
5696 pSMB->ParameterCount = cpu_to_le16(params);
5697 pSMB->TotalDataCount = pSMB->DataCount;
5698 pSMB->TotalParameterCount = pSMB->ParameterCount;
5699 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5700 pSMB->DataOffset = cpu_to_le16(offset);
5701 pSMB->Fid = fid;
5702 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5703 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5704 else
5705 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5706 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005707 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005708 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005709 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Steve French133672e2007-11-13 22:41:37 +00005710 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005711 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005712 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005713
Steve French50c2f752007-07-13 00:33:32 +00005714 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005715 since file handle passed in no longer valid */
5716
5717 return rc;
5718}
5719
Jeff Layton6d22f092008-09-23 11:48:35 -04005720int
Steve French96daf2b2011-05-27 04:34:02 +00005721CIFSSMBSetFileDisposition(const int xid, struct cifs_tcon *tcon,
Jeff Layton6d22f092008-09-23 11:48:35 -04005722 bool delete_file, __u16 fid, __u32 pid_of_opener)
5723{
5724 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5725 char *data_offset;
5726 int rc = 0;
5727 __u16 params, param_offset, offset, byte_count, count;
5728
Joe Perchesb6b38f72010-04-21 03:50:45 +00005729 cFYI(1, "Set File Disposition (via SetFileInfo)");
Jeff Layton6d22f092008-09-23 11:48:35 -04005730 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5731
5732 if (rc)
5733 return rc;
5734
5735 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5736 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5737
5738 params = 6;
5739 pSMB->MaxSetupCount = 0;
5740 pSMB->Reserved = 0;
5741 pSMB->Flags = 0;
5742 pSMB->Timeout = 0;
5743 pSMB->Reserved2 = 0;
5744 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5745 offset = param_offset + params;
5746
5747 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5748
5749 count = 1;
5750 pSMB->MaxParameterCount = cpu_to_le16(2);
5751 /* BB find max SMB PDU from sess */
5752 pSMB->MaxDataCount = cpu_to_le16(1000);
5753 pSMB->SetupCount = 1;
5754 pSMB->Reserved3 = 0;
5755 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5756 byte_count = 3 /* pad */ + params + count;
5757 pSMB->DataCount = cpu_to_le16(count);
5758 pSMB->ParameterCount = cpu_to_le16(params);
5759 pSMB->TotalDataCount = pSMB->DataCount;
5760 pSMB->TotalParameterCount = pSMB->ParameterCount;
5761 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5762 pSMB->DataOffset = cpu_to_le16(offset);
5763 pSMB->Fid = fid;
5764 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5765 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005766 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton6d22f092008-09-23 11:48:35 -04005767 pSMB->ByteCount = cpu_to_le16(byte_count);
5768 *data_offset = delete_file ? 1 : 0;
5769 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
5770 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005771 cFYI(1, "Send error in SetFileDisposition = %d", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005772
5773 return rc;
5774}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005775
5776int
Steve French96daf2b2011-05-27 04:34:02 +00005777CIFSSMBSetPathInfo(const int xid, struct cifs_tcon *tcon,
Jeff Layton6fc000e2008-08-02 07:26:12 -04005778 const char *fileName, const FILE_BASIC_INFO *data,
5779 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005780{
5781 TRANSACTION2_SPI_REQ *pSMB = NULL;
5782 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5783 int name_len;
5784 int rc = 0;
5785 int bytes_returned = 0;
5786 char *data_offset;
5787 __u16 params, param_offset, offset, byte_count, count;
5788
Joe Perchesb6b38f72010-04-21 03:50:45 +00005789 cFYI(1, "In SetTimes");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005790
5791SetTimesRetry:
5792 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5793 (void **) &pSMBr);
5794 if (rc)
5795 return rc;
5796
5797 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5798 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05005799 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005800 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005801 name_len++; /* trailing null */
5802 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005803 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005804 name_len = strnlen(fileName, PATH_MAX);
5805 name_len++; /* trailing null */
5806 strncpy(pSMB->FileName, fileName, name_len);
5807 }
5808
5809 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005810 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005811 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005812 /* BB find max SMB PDU from sess structure BB */
5813 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005814 pSMB->MaxSetupCount = 0;
5815 pSMB->Reserved = 0;
5816 pSMB->Flags = 0;
5817 pSMB->Timeout = 0;
5818 pSMB->Reserved2 = 0;
5819 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005820 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005821 offset = param_offset + params;
5822 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5823 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5824 pSMB->DataOffset = cpu_to_le16(offset);
5825 pSMB->SetupCount = 1;
5826 pSMB->Reserved3 = 0;
5827 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5828 byte_count = 3 /* pad */ + params + count;
5829
5830 pSMB->DataCount = cpu_to_le16(count);
5831 pSMB->ParameterCount = cpu_to_le16(params);
5832 pSMB->TotalDataCount = pSMB->DataCount;
5833 pSMB->TotalParameterCount = pSMB->ParameterCount;
5834 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5835 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5836 else
5837 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5838 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005839 inc_rfc1001_len(pSMB, byte_count);
Steve French26f57362007-08-30 22:09:15 +00005840 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005841 pSMB->ByteCount = cpu_to_le16(byte_count);
5842 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5843 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005844 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005845 cFYI(1, "SetPathInfo (times) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005846
5847 cifs_buf_release(pSMB);
5848
5849 if (rc == -EAGAIN)
5850 goto SetTimesRetry;
5851
5852 return rc;
5853}
5854
5855/* Can not be used to set time stamps yet (due to old DOS time format) */
5856/* Can be used to set attributes */
5857#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5858 handling it anyway and NT4 was what we thought it would be needed for
5859 Do not delete it until we prove whether needed for Win9x though */
5860int
Steve French96daf2b2011-05-27 04:34:02 +00005861CIFSSMBSetAttrLegacy(int xid, struct cifs_tcon *tcon, char *fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005862 __u16 dos_attrs, const struct nls_table *nls_codepage)
5863{
5864 SETATTR_REQ *pSMB = NULL;
5865 SETATTR_RSP *pSMBr = NULL;
5866 int rc = 0;
5867 int bytes_returned;
5868 int name_len;
5869
Joe Perchesb6b38f72010-04-21 03:50:45 +00005870 cFYI(1, "In SetAttrLegacy");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005871
5872SetAttrLgcyRetry:
5873 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5874 (void **) &pSMBr);
5875 if (rc)
5876 return rc;
5877
5878 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5879 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005880 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005881 PATH_MAX, nls_codepage);
5882 name_len++; /* trailing null */
5883 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005884 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005885 name_len = strnlen(fileName, PATH_MAX);
5886 name_len++; /* trailing null */
5887 strncpy(pSMB->fileName, fileName, name_len);
5888 }
5889 pSMB->attr = cpu_to_le16(dos_attrs);
5890 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005891 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005892 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5893 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5894 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005895 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005896 cFYI(1, "Error in LegacySetAttr = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005897
5898 cifs_buf_release(pSMB);
5899
5900 if (rc == -EAGAIN)
5901 goto SetAttrLgcyRetry;
5902
5903 return rc;
5904}
5905#endif /* temporarily unneeded SetAttr legacy function */
5906
Jeff Layton654cf142009-07-09 20:02:49 -04005907static void
5908cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5909 const struct cifs_unix_set_info_args *args)
5910{
5911 u64 mode = args->mode;
5912
5913 /*
5914 * Samba server ignores set of file size to zero due to bugs in some
5915 * older clients, but we should be precise - we use SetFileSize to
5916 * set file size and do not want to truncate file size to zero
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005917 * accidentally as happened on one Samba server beta by putting
Jeff Layton654cf142009-07-09 20:02:49 -04005918 * zero instead of -1 here
5919 */
5920 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5921 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5922 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5923 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5924 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5925 data_offset->Uid = cpu_to_le64(args->uid);
5926 data_offset->Gid = cpu_to_le64(args->gid);
5927 /* better to leave device as zero when it is */
5928 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5929 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5930 data_offset->Permissions = cpu_to_le64(mode);
5931
5932 if (S_ISREG(mode))
5933 data_offset->Type = cpu_to_le32(UNIX_FILE);
5934 else if (S_ISDIR(mode))
5935 data_offset->Type = cpu_to_le32(UNIX_DIR);
5936 else if (S_ISLNK(mode))
5937 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5938 else if (S_ISCHR(mode))
5939 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5940 else if (S_ISBLK(mode))
5941 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5942 else if (S_ISFIFO(mode))
5943 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5944 else if (S_ISSOCK(mode))
5945 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5946}
5947
Linus Torvalds1da177e2005-04-16 15:20:36 -07005948int
Steve French96daf2b2011-05-27 04:34:02 +00005949CIFSSMBUnixSetFileInfo(const int xid, struct cifs_tcon *tcon,
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005950 const struct cifs_unix_set_info_args *args,
5951 u16 fid, u32 pid_of_opener)
5952{
5953 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5954 FILE_UNIX_BASIC_INFO *data_offset;
5955 int rc = 0;
5956 u16 params, param_offset, offset, byte_count, count;
5957
Joe Perchesb6b38f72010-04-21 03:50:45 +00005958 cFYI(1, "Set Unix Info (via SetFileInfo)");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005959 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5960
5961 if (rc)
5962 return rc;
5963
5964 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5965 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5966
5967 params = 6;
5968 pSMB->MaxSetupCount = 0;
5969 pSMB->Reserved = 0;
5970 pSMB->Flags = 0;
5971 pSMB->Timeout = 0;
5972 pSMB->Reserved2 = 0;
5973 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5974 offset = param_offset + params;
5975
5976 data_offset = (FILE_UNIX_BASIC_INFO *)
5977 ((char *)(&pSMB->hdr.Protocol) + offset);
5978 count = sizeof(FILE_UNIX_BASIC_INFO);
5979
5980 pSMB->MaxParameterCount = cpu_to_le16(2);
5981 /* BB find max SMB PDU from sess */
5982 pSMB->MaxDataCount = cpu_to_le16(1000);
5983 pSMB->SetupCount = 1;
5984 pSMB->Reserved3 = 0;
5985 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5986 byte_count = 3 /* pad */ + params + count;
5987 pSMB->DataCount = cpu_to_le16(count);
5988 pSMB->ParameterCount = cpu_to_le16(params);
5989 pSMB->TotalDataCount = pSMB->DataCount;
5990 pSMB->TotalParameterCount = pSMB->ParameterCount;
5991 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5992 pSMB->DataOffset = cpu_to_le16(offset);
5993 pSMB->Fid = fid;
5994 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5995 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005996 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005997 pSMB->ByteCount = cpu_to_le16(byte_count);
5998
5999 cifs_fill_unix_set_info(data_offset, args);
6000
6001 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
6002 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00006003 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006004
6005 /* Note: On -EAGAIN error only caller can retry on handle based calls
6006 since file handle passed in no longer valid */
6007
6008 return rc;
6009}
6010
6011int
Steve French96daf2b2011-05-27 04:34:02 +00006012CIFSSMBUnixSetPathInfo(const int xid, struct cifs_tcon *tcon, char *fileName,
Jeff Layton01ea95e2009-07-09 20:02:49 -04006013 const struct cifs_unix_set_info_args *args,
6014 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006015{
6016 TRANSACTION2_SPI_REQ *pSMB = NULL;
6017 TRANSACTION2_SPI_RSP *pSMBr = NULL;
6018 int name_len;
6019 int rc = 0;
6020 int bytes_returned = 0;
6021 FILE_UNIX_BASIC_INFO *data_offset;
6022 __u16 params, param_offset, offset, count, byte_count;
6023
Joe Perchesb6b38f72010-04-21 03:50:45 +00006024 cFYI(1, "In SetUID/GID/Mode");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006025setPermsRetry:
6026 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6027 (void **) &pSMBr);
6028 if (rc)
6029 return rc;
6030
6031 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6032 name_len =
Steve French50c2f752007-07-13 00:33:32 +00006033 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07006034 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006035 name_len++; /* trailing null */
6036 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07006037 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006038 name_len = strnlen(fileName, PATH_MAX);
6039 name_len++; /* trailing null */
6040 strncpy(pSMB->FileName, fileName, name_len);
6041 }
6042
6043 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00006044 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006045 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006046 /* BB find max SMB PDU from sess structure BB */
6047 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006048 pSMB->MaxSetupCount = 0;
6049 pSMB->Reserved = 0;
6050 pSMB->Flags = 0;
6051 pSMB->Timeout = 0;
6052 pSMB->Reserved2 = 0;
6053 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006054 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006055 offset = param_offset + params;
6056 data_offset =
6057 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
6058 offset);
6059 memset(data_offset, 0, count);
6060 pSMB->DataOffset = cpu_to_le16(offset);
6061 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6062 pSMB->SetupCount = 1;
6063 pSMB->Reserved3 = 0;
6064 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6065 byte_count = 3 /* pad */ + params + count;
6066 pSMB->ParameterCount = cpu_to_le16(params);
6067 pSMB->DataCount = cpu_to_le16(count);
6068 pSMB->TotalParameterCount = pSMB->ParameterCount;
6069 pSMB->TotalDataCount = pSMB->DataCount;
6070 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6071 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006072 inc_rfc1001_len(pSMB, byte_count);
Steve French50c2f752007-07-13 00:33:32 +00006073
Jeff Layton654cf142009-07-09 20:02:49 -04006074 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006075
6076 pSMB->ByteCount = cpu_to_le16(byte_count);
6077 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6078 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006079 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00006080 cFYI(1, "SetPathInfo (perms) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006081
Steve French0d817bc2008-05-22 02:02:03 +00006082 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006083 if (rc == -EAGAIN)
6084 goto setPermsRetry;
6085 return rc;
6086}
6087
Linus Torvalds1da177e2005-04-16 15:20:36 -07006088#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05006089/*
6090 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
6091 * function used by listxattr and getxattr type calls. When ea_name is set,
6092 * it looks for that attribute name and stuffs that value into the EAData
6093 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
6094 * buffer. In both cases, the return value is either the length of the
6095 * resulting data or a negative error code. If EAData is a NULL pointer then
6096 * the data isn't copied to it, but the length is returned.
6097 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006098ssize_t
Steve French96daf2b2011-05-27 04:34:02 +00006099CIFSSMBQAllEAs(const int xid, struct cifs_tcon *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05006100 const unsigned char *searchName, const unsigned char *ea_name,
6101 char *EAData, size_t buf_size,
6102 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006103{
6104 /* BB assumes one setup word */
6105 TRANSACTION2_QPI_REQ *pSMB = NULL;
6106 TRANSACTION2_QPI_RSP *pSMBr = NULL;
6107 int rc = 0;
6108 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05006109 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006110 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00006111 struct fea *temp_fea;
6112 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006113 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006114 __u16 params, byte_count, data_offset;
Jeff Layton5980fc92011-07-28 12:48:26 -04006115 unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006116
Joe Perchesb6b38f72010-04-21 03:50:45 +00006117 cFYI(1, "In Query All EAs path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006118QAllEAsRetry:
6119 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6120 (void **) &pSMBr);
6121 if (rc)
6122 return rc;
6123
6124 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05006125 list_len =
Steve French50c2f752007-07-13 00:33:32 +00006126 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07006127 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05006128 list_len++; /* trailing null */
6129 list_len *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006130 } else { /* BB improve the check for buffer overruns BB */
Jeff Layton6e462b92010-02-10 16:18:26 -05006131 list_len = strnlen(searchName, PATH_MAX);
6132 list_len++; /* trailing null */
6133 strncpy(pSMB->FileName, searchName, list_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006134 }
6135
Jeff Layton6e462b92010-02-10 16:18:26 -05006136 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006137 pSMB->TotalDataCount = 0;
6138 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006139 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05006140 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006141 pSMB->MaxSetupCount = 0;
6142 pSMB->Reserved = 0;
6143 pSMB->Flags = 0;
6144 pSMB->Timeout = 0;
6145 pSMB->Reserved2 = 0;
6146 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00006147 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006148 pSMB->DataCount = 0;
6149 pSMB->DataOffset = 0;
6150 pSMB->SetupCount = 1;
6151 pSMB->Reserved3 = 0;
6152 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
6153 byte_count = params + 1 /* pad */ ;
6154 pSMB->TotalParameterCount = cpu_to_le16(params);
6155 pSMB->ParameterCount = pSMB->TotalParameterCount;
6156 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
6157 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006158 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006159 pSMB->ByteCount = cpu_to_le16(byte_count);
6160
6161 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6162 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6163 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006164 cFYI(1, "Send error in QueryAllEAs = %d", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05006165 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006166 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006167
6168
6169 /* BB also check enough total bytes returned */
6170 /* BB we need to improve the validity checking
6171 of these trans2 responses */
6172
6173 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Jeff Layton820a8032011-05-04 08:05:26 -04006174 if (rc || get_bcc(&pSMBr->hdr) < 4) {
Jeff Laytonf0d38682010-02-10 16:18:26 -05006175 rc = -EIO; /* bad smb */
6176 goto QAllEAsOut;
6177 }
6178
6179 /* check that length of list is not more than bcc */
6180 /* check that each entry does not go beyond length
6181 of list */
6182 /* check that each element of each entry does not
6183 go beyond end of list */
6184 /* validate_trans2_offsets() */
6185 /* BB check if start of smb + data_offset > &bcc+ bcc */
6186
6187 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
6188 ea_response_data = (struct fealist *)
6189 (((char *) &pSMBr->hdr.Protocol) + data_offset);
6190
Jeff Layton6e462b92010-02-10 16:18:26 -05006191 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesb6b38f72010-04-21 03:50:45 +00006192 cFYI(1, "ea length %d", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05006193 if (list_len <= 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006194 cFYI(1, "empty EA list returned from server");
Jeff Laytonf0d38682010-02-10 16:18:26 -05006195 goto QAllEAsOut;
6196 }
6197
Jeff Layton0cd126b2010-02-10 16:18:26 -05006198 /* make sure list_len doesn't go past end of SMB */
Jeff Layton690c5222011-01-20 13:36:51 -05006199 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
Jeff Layton0cd126b2010-02-10 16:18:26 -05006200 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006201 cFYI(1, "EA list appears to go beyond SMB");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006202 rc = -EIO;
6203 goto QAllEAsOut;
6204 }
6205
Jeff Laytonf0d38682010-02-10 16:18:26 -05006206 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05006207 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006208 temp_fea = ea_response_data->list;
6209 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05006210 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00006211 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006212 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006213
Jeff Layton6e462b92010-02-10 16:18:26 -05006214 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006215 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006216 /* make sure we can read name_len and value_len */
6217 if (list_len < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006218 cFYI(1, "EA entry goes beyond length of list");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006219 rc = -EIO;
6220 goto QAllEAsOut;
6221 }
6222
6223 name_len = temp_fea->name_len;
6224 value_len = le16_to_cpu(temp_fea->value_len);
6225 list_len -= name_len + 1 + value_len;
6226 if (list_len < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006227 cFYI(1, "EA entry goes beyond length of list");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006228 rc = -EIO;
6229 goto QAllEAsOut;
6230 }
6231
Jeff Layton31c05192010-02-10 16:18:26 -05006232 if (ea_name) {
Jeff Layton91d065c2011-07-26 18:23:47 -04006233 if (ea_name_len == name_len &&
Jeff Laytonac423442011-10-11 06:41:32 -04006234 memcmp(ea_name, temp_ptr, name_len) == 0) {
Jeff Layton31c05192010-02-10 16:18:26 -05006235 temp_ptr += name_len + 1;
6236 rc = value_len;
6237 if (buf_size == 0)
6238 goto QAllEAsOut;
6239 if ((size_t)value_len > buf_size) {
6240 rc = -ERANGE;
6241 goto QAllEAsOut;
6242 }
6243 memcpy(EAData, temp_ptr, value_len);
6244 goto QAllEAsOut;
6245 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006246 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05006247 /* account for prefix user. and trailing null */
6248 rc += (5 + 1 + name_len);
6249 if (rc < (int) buf_size) {
6250 memcpy(EAData, "user.", 5);
6251 EAData += 5;
6252 memcpy(EAData, temp_ptr, name_len);
6253 EAData += name_len;
6254 /* null terminate name */
6255 *EAData = 0;
6256 ++EAData;
6257 } else if (buf_size == 0) {
6258 /* skip copy - calc size only */
6259 } else {
6260 /* stop before overrun buffer */
6261 rc = -ERANGE;
6262 break;
6263 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006264 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05006265 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006266 temp_fea = (struct fea *)temp_ptr;
6267 }
6268
Jeff Layton31c05192010-02-10 16:18:26 -05006269 /* didn't find the named attribute */
6270 if (ea_name)
6271 rc = -ENODATA;
6272
Jeff Laytonf0d38682010-02-10 16:18:26 -05006273QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00006274 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006275 if (rc == -EAGAIN)
6276 goto QAllEAsRetry;
6277
6278 return (ssize_t)rc;
6279}
6280
Linus Torvalds1da177e2005-04-16 15:20:36 -07006281int
Steve French96daf2b2011-05-27 04:34:02 +00006282CIFSSMBSetEA(const int xid, struct cifs_tcon *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00006283 const char *ea_name, const void *ea_value,
6284 const __u16 ea_value_len, const struct nls_table *nls_codepage,
6285 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006286{
6287 struct smb_com_transaction2_spi_req *pSMB = NULL;
6288 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
6289 struct fealist *parm_data;
6290 int name_len;
6291 int rc = 0;
6292 int bytes_returned = 0;
6293 __u16 params, param_offset, byte_count, offset, count;
6294
Joe Perchesb6b38f72010-04-21 03:50:45 +00006295 cFYI(1, "In SetEA");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006296SetEARetry:
6297 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6298 (void **) &pSMBr);
6299 if (rc)
6300 return rc;
6301
6302 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6303 name_len =
Steve French50c2f752007-07-13 00:33:32 +00006304 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07006305 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006306 name_len++; /* trailing null */
6307 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00006308 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006309 name_len = strnlen(fileName, PATH_MAX);
6310 name_len++; /* trailing null */
6311 strncpy(pSMB->FileName, fileName, name_len);
6312 }
6313
6314 params = 6 + name_len;
6315
6316 /* done calculating parms using name_len of file name,
6317 now use name_len to calculate length of ea name
6318 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00006319 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006320 name_len = 0;
6321 else
Steve French50c2f752007-07-13 00:33:32 +00006322 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006323
Steve Frenchdae5dbdb2007-12-30 23:49:57 +00006324 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006325 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006326 /* BB find max SMB PDU from sess */
6327 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006328 pSMB->MaxSetupCount = 0;
6329 pSMB->Reserved = 0;
6330 pSMB->Flags = 0;
6331 pSMB->Timeout = 0;
6332 pSMB->Reserved2 = 0;
6333 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006334 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006335 offset = param_offset + params;
6336 pSMB->InformationLevel =
6337 cpu_to_le16(SMB_SET_FILE_EA);
6338
6339 parm_data =
6340 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
6341 offset);
6342 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6343 pSMB->DataOffset = cpu_to_le16(offset);
6344 pSMB->SetupCount = 1;
6345 pSMB->Reserved3 = 0;
6346 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6347 byte_count = 3 /* pad */ + params + count;
6348 pSMB->DataCount = cpu_to_le16(count);
6349 parm_data->list_len = cpu_to_le32(count);
6350 parm_data->list[0].EA_flags = 0;
6351 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08006352 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006353 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00006354 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00006355 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006356 parm_data->list[0].name[name_len] = 0;
6357 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
6358 /* caller ensures that ea_value_len is less than 64K but
6359 we need to ensure that it fits within the smb */
6360
Steve French50c2f752007-07-13 00:33:32 +00006361 /*BB add length check to see if it would fit in
6362 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00006363 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
6364 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00006365 memcpy(parm_data->list[0].name+name_len+1,
6366 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006367
6368 pSMB->TotalDataCount = pSMB->DataCount;
6369 pSMB->ParameterCount = cpu_to_le16(params);
6370 pSMB->TotalParameterCount = pSMB->ParameterCount;
6371 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006372 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006373 pSMB->ByteCount = cpu_to_le16(byte_count);
6374 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6375 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006376 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00006377 cFYI(1, "SetPathInfo (EA) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006378
6379 cifs_buf_release(pSMB);
6380
6381 if (rc == -EAGAIN)
6382 goto SetEARetry;
6383
6384 return rc;
6385}
Linus Torvalds1da177e2005-04-16 15:20:36 -07006386#endif
Steve French0eff0e22011-02-24 05:39:23 +00006387
6388#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */
6389/*
6390 * Years ago the kernel added a "dnotify" function for Samba server,
6391 * to allow network clients (such as Windows) to display updated
6392 * lists of files in directory listings automatically when
6393 * files are added by one user when another user has the
6394 * same directory open on their desktop. The Linux cifs kernel
6395 * client hooked into the kernel side of this interface for
6396 * the same reason, but ironically when the VFS moved from
6397 * "dnotify" to "inotify" it became harder to plug in Linux
6398 * network file system clients (the most obvious use case
6399 * for notify interfaces is when multiple users can update
6400 * the contents of the same directory - exactly what network
6401 * file systems can do) although the server (Samba) could
6402 * still use it. For the short term we leave the worker
6403 * function ifdeffed out (below) until inotify is fixed
6404 * in the VFS to make it easier to plug in network file
6405 * system clients. If inotify turns out to be permanently
6406 * incompatible for network fs clients, we could instead simply
6407 * expose this config flag by adding a future cifs (and smb2) notify ioctl.
6408 */
Steve French96daf2b2011-05-27 04:34:02 +00006409int CIFSSMBNotify(const int xid, struct cifs_tcon *tcon,
Steve French0eff0e22011-02-24 05:39:23 +00006410 const int notify_subdirs, const __u16 netfid,
6411 __u32 filter, struct file *pfile, int multishot,
6412 const struct nls_table *nls_codepage)
6413{
6414 int rc = 0;
6415 struct smb_com_transaction_change_notify_req *pSMB = NULL;
6416 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
6417 struct dir_notify_req *dnotify_req;
6418 int bytes_returned;
6419
6420 cFYI(1, "In CIFSSMBNotify for file handle %d", (int)netfid);
6421 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
6422 (void **) &pSMBr);
6423 if (rc)
6424 return rc;
6425
6426 pSMB->TotalParameterCount = 0 ;
6427 pSMB->TotalDataCount = 0;
6428 pSMB->MaxParameterCount = cpu_to_le32(2);
Jeff Laytonc974bef2011-10-11 06:41:32 -04006429 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Steve French0eff0e22011-02-24 05:39:23 +00006430 pSMB->MaxSetupCount = 4;
6431 pSMB->Reserved = 0;
6432 pSMB->ParameterOffset = 0;
6433 pSMB->DataCount = 0;
6434 pSMB->DataOffset = 0;
6435 pSMB->SetupCount = 4; /* single byte does not need le conversion */
6436 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
6437 pSMB->ParameterCount = pSMB->TotalParameterCount;
6438 if (notify_subdirs)
6439 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
6440 pSMB->Reserved2 = 0;
6441 pSMB->CompletionFilter = cpu_to_le32(filter);
6442 pSMB->Fid = netfid; /* file handle always le */
6443 pSMB->ByteCount = 0;
6444
6445 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6446 (struct smb_hdr *)pSMBr, &bytes_returned,
6447 CIFS_ASYNC_OP);
6448 if (rc) {
6449 cFYI(1, "Error in Notify = %d", rc);
6450 } else {
6451 /* Add file to outstanding requests */
6452 /* BB change to kmem cache alloc */
6453 dnotify_req = kmalloc(
6454 sizeof(struct dir_notify_req),
6455 GFP_KERNEL);
6456 if (dnotify_req) {
6457 dnotify_req->Pid = pSMB->hdr.Pid;
6458 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
6459 dnotify_req->Mid = pSMB->hdr.Mid;
6460 dnotify_req->Tid = pSMB->hdr.Tid;
6461 dnotify_req->Uid = pSMB->hdr.Uid;
6462 dnotify_req->netfid = netfid;
6463 dnotify_req->pfile = pfile;
6464 dnotify_req->filter = filter;
6465 dnotify_req->multishot = multishot;
6466 spin_lock(&GlobalMid_Lock);
6467 list_add_tail(&dnotify_req->lhead,
6468 &GlobalDnotifyReqList);
6469 spin_unlock(&GlobalMid_Lock);
6470 } else
6471 rc = -ENOMEM;
6472 }
6473 cifs_buf_release(pSMB);
6474 return rc;
6475}
6476#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */