blob: 77463f701f017578cd5eca197443882dc850d5ed [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 */
Jeff Laytone28bc5b2011-10-19 15:30:07 -040090
Linus Torvalds1da177e2005-04-16 15:20:36 -070091/* Mark as invalid, all open files on tree connections since they
92 were closed when session to server was lost */
Steve French96daf2b2011-05-27 04:34:02 +000093static void mark_open_files_invalid(struct cifs_tcon *pTcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -070094{
95 struct cifsFileInfo *open_file = NULL;
Steve French790fe572007-07-07 19:25:05 +000096 struct list_head *tmp;
97 struct list_head *tmp1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070098
99/* list all files open on tree connection and mark them invalid */
Jeff Layton44772882010-10-15 15:34:03 -0400100 spin_lock(&cifs_file_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101 list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
Steve French790fe572007-07-07 19:25:05 +0000102 open_file = list_entry(tmp, struct cifsFileInfo, tlist);
Steve Frenchad8b15f2008-08-08 21:10:16 +0000103 open_file->invalidHandle = true;
Jeff Layton3bc303c2009-09-21 06:47:50 -0400104 open_file->oplock_break_cancelled = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105 }
Jeff Layton44772882010-10-15 15:34:03 -0400106 spin_unlock(&cifs_file_list_lock);
Steve French09d1db52005-04-28 22:41:08 -0700107 /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
108 to this tcon */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109}
110
Jeff Layton9162ab22009-09-03 12:07:17 -0400111/* reconnect the socket, tcon, and smb session if needed */
112static int
Steve French96daf2b2011-05-27 04:34:02 +0000113cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
Jeff Layton9162ab22009-09-03 12:07:17 -0400114{
Jeff Laytonc4a55342011-07-28 12:40:36 -0400115 int rc;
Steve French96daf2b2011-05-27 04:34:02 +0000116 struct cifs_ses *ses;
Jeff Layton9162ab22009-09-03 12:07:17 -0400117 struct TCP_Server_Info *server;
118 struct nls_table *nls_codepage;
119
120 /*
121 * SMBs NegProt, SessSetup, uLogoff do not have tcon yet so check for
122 * tcp and smb session status done differently for those three - in the
123 * calling routine
124 */
125 if (!tcon)
126 return 0;
127
128 ses = tcon->ses;
129 server = ses->server;
130
131 /*
132 * only tree disconnect, open, and write, (and ulogoff which does not
133 * have tcon) are allowed as we start force umount
134 */
135 if (tcon->tidStatus == CifsExiting) {
136 if (smb_command != SMB_COM_WRITE_ANDX &&
137 smb_command != SMB_COM_OPEN_ANDX &&
138 smb_command != SMB_COM_TREE_DISCONNECT) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000139 cFYI(1, "can not send cmd %d while umounting",
140 smb_command);
Jeff Layton9162ab22009-09-03 12:07:17 -0400141 return -ENODEV;
142 }
143 }
144
Jeff Layton9162ab22009-09-03 12:07:17 -0400145 /*
146 * Give demultiplex thread up to 10 seconds to reconnect, should be
147 * greater than cifs socket timeout which is 7 seconds
148 */
149 while (server->tcpStatus == CifsNeedReconnect) {
150 wait_event_interruptible_timeout(server->response_q,
Steve Frenchfd88ce92011-04-12 01:01:14 +0000151 (server->tcpStatus != CifsNeedReconnect), 10 * HZ);
Jeff Layton9162ab22009-09-03 12:07:17 -0400152
Steve Frenchfd88ce92011-04-12 01:01:14 +0000153 /* are we still trying to reconnect? */
Jeff Layton9162ab22009-09-03 12:07:17 -0400154 if (server->tcpStatus != CifsNeedReconnect)
155 break;
156
157 /*
158 * on "soft" mounts we wait once. Hard mounts keep
159 * retrying until process is killed or server comes
160 * back on-line
161 */
Jeff Laytond4025392011-02-07 08:54:35 -0500162 if (!tcon->retry) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000163 cFYI(1, "gave up waiting on reconnect in smb_init");
Jeff Layton9162ab22009-09-03 12:07:17 -0400164 return -EHOSTDOWN;
165 }
166 }
167
168 if (!ses->need_reconnect && !tcon->need_reconnect)
169 return 0;
170
171 nls_codepage = load_nls_default();
172
173 /*
174 * need to prevent multiple threads trying to simultaneously
175 * reconnect the same SMB session
176 */
Steve Frenchd7b619c2010-02-25 05:36:46 +0000177 mutex_lock(&ses->session_mutex);
Jeff Layton198b5682010-04-24 07:57:48 -0400178 rc = cifs_negotiate_protocol(0, ses);
179 if (rc == 0 && ses->need_reconnect)
Jeff Layton9162ab22009-09-03 12:07:17 -0400180 rc = cifs_setup_session(0, ses, nls_codepage);
181
182 /* do we need to reconnect tcon? */
183 if (rc || !tcon->need_reconnect) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000184 mutex_unlock(&ses->session_mutex);
Jeff Layton9162ab22009-09-03 12:07:17 -0400185 goto out;
186 }
187
188 mark_open_files_invalid(tcon);
189 rc = CIFSTCon(0, ses, tcon->treeName, tcon, nls_codepage);
Steve Frenchd7b619c2010-02-25 05:36:46 +0000190 mutex_unlock(&ses->session_mutex);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000191 cFYI(1, "reconnect tcon rc = %d", rc);
Jeff Layton9162ab22009-09-03 12:07:17 -0400192
193 if (rc)
194 goto out;
195
196 /*
197 * FIXME: check if wsize needs updated due to negotiated smb buffer
198 * size shrinking
199 */
200 atomic_inc(&tconInfoReconnectCount);
201
202 /* tell server Unix caps we support */
203 if (ses->capabilities & CAP_UNIX)
204 reset_cifs_unix_caps(0, tcon, NULL, NULL);
205
206 /*
207 * Removed call to reopen open files here. It is safer (and faster) to
208 * reopen files one at a time as needed in read and write.
209 *
210 * FIXME: what about file locks? don't we need to reclaim them ASAP?
211 */
212
213out:
214 /*
215 * Check if handle based operation so we know whether we can continue
216 * or not without returning to caller to reset file handle
217 */
218 switch (smb_command) {
219 case SMB_COM_READ_ANDX:
220 case SMB_COM_WRITE_ANDX:
221 case SMB_COM_CLOSE:
222 case SMB_COM_FIND_CLOSE2:
223 case SMB_COM_LOCKING_ANDX:
224 rc = -EAGAIN;
225 }
226
227 unload_nls(nls_codepage);
228 return rc;
229}
230
Steve Frenchad7a2922008-02-07 23:25:02 +0000231/* Allocate and return pointer to an SMB request buffer, and set basic
232 SMB information in the SMB header. If the return code is zero, this
233 function must have filled in request_buf pointer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234static int
Steve French96daf2b2011-05-27 04:34:02 +0000235small_smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000236 void **request_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237{
Jeff Laytonf5695992010-09-29 15:27:08 -0400238 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239
Jeff Layton9162ab22009-09-03 12:07:17 -0400240 rc = cifs_reconnect_tcon(tcon, smb_command);
Steve French790fe572007-07-07 19:25:05 +0000241 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242 return rc;
243
244 *request_buf = cifs_small_buf_get();
245 if (*request_buf == NULL) {
246 /* BB should we add a retry in here if not a writepage? */
247 return -ENOMEM;
248 }
249
Steve French63135e02007-07-17 17:34:02 +0000250 header_assemble((struct smb_hdr *) *request_buf, smb_command,
Steve Frenchc18c8422007-07-18 23:21:09 +0000251 tcon, wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252
Steve French790fe572007-07-07 19:25:05 +0000253 if (tcon != NULL)
254 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700255
Jeff Laytonf5695992010-09-29 15:27:08 -0400256 return 0;
Steve French5815449d2006-02-14 01:36:20 +0000257}
258
Steve French12b3b8f2006-02-09 21:12:47 +0000259int
Steve French50c2f752007-07-13 00:33:32 +0000260small_smb_init_no_tc(const int smb_command, const int wct,
Steve French96daf2b2011-05-27 04:34:02 +0000261 struct cifs_ses *ses, void **request_buf)
Steve French12b3b8f2006-02-09 21:12:47 +0000262{
263 int rc;
Steve French50c2f752007-07-13 00:33:32 +0000264 struct smb_hdr *buffer;
Steve French12b3b8f2006-02-09 21:12:47 +0000265
Steve French5815449d2006-02-14 01:36:20 +0000266 rc = small_smb_init(smb_command, wct, NULL, request_buf);
Steve French790fe572007-07-07 19:25:05 +0000267 if (rc)
Steve French12b3b8f2006-02-09 21:12:47 +0000268 return rc;
269
Steve French04fdabe2006-02-10 05:52:50 +0000270 buffer = (struct smb_hdr *)*request_buf;
Steve French12b3b8f2006-02-09 21:12:47 +0000271 buffer->Mid = GetNextMid(ses->server);
272 if (ses->capabilities & CAP_UNICODE)
273 buffer->Flags2 |= SMBFLG2_UNICODE;
Steve French04fdabe2006-02-10 05:52:50 +0000274 if (ses->capabilities & CAP_STATUS32)
Steve French12b3b8f2006-02-09 21:12:47 +0000275 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
276
277 /* uid, tid can stay at zero as set in header assemble */
278
Steve French50c2f752007-07-13 00:33:32 +0000279 /* BB add support for turning on the signing when
Steve French12b3b8f2006-02-09 21:12:47 +0000280 this function is used after 1st of session setup requests */
281
282 return rc;
283}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284
285/* If the return code is zero, this function must fill in request_buf pointer */
286static int
Steve French96daf2b2011-05-27 04:34:02 +0000287__smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400288 void **request_buf, void **response_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290 *request_buf = cifs_buf_get();
291 if (*request_buf == NULL) {
292 /* BB should we add a retry in here if not a writepage? */
293 return -ENOMEM;
294 }
295 /* Although the original thought was we needed the response buf for */
296 /* potential retries of smb operations it turns out we can determine */
297 /* from the mid flags when the request buffer can be resent without */
298 /* having to use a second distinct buffer for the response */
Steve French790fe572007-07-07 19:25:05 +0000299 if (response_buf)
Steve French50c2f752007-07-13 00:33:32 +0000300 *response_buf = *request_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301
302 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000303 wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304
Steve French790fe572007-07-07 19:25:05 +0000305 if (tcon != NULL)
306 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700307
Jeff Laytonf5695992010-09-29 15:27:08 -0400308 return 0;
309}
310
311/* If the return code is zero, this function must fill in request_buf pointer */
312static int
Steve French96daf2b2011-05-27 04:34:02 +0000313smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400314 void **request_buf, void **response_buf)
315{
316 int rc;
317
318 rc = cifs_reconnect_tcon(tcon, smb_command);
319 if (rc)
320 return rc;
321
322 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
323}
324
325static int
Steve French96daf2b2011-05-27 04:34:02 +0000326smb_init_no_reconnect(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400327 void **request_buf, void **response_buf)
328{
329 if (tcon->ses->need_reconnect || tcon->need_reconnect)
330 return -EHOSTDOWN;
331
332 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333}
334
Steve French50c2f752007-07-13 00:33:32 +0000335static int validate_t2(struct smb_t2_rsp *pSMB)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336{
Jeff Layton12df83c2011-01-20 13:36:51 -0500337 unsigned int total_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338
Jeff Layton12df83c2011-01-20 13:36:51 -0500339 /* check for plausible wct */
340 if (pSMB->hdr.WordCount < 10)
341 goto vt2_err;
342
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343 /* check for parm and data offset going beyond end of smb */
Jeff Layton12df83c2011-01-20 13:36:51 -0500344 if (get_unaligned_le16(&pSMB->t2_rsp.ParameterOffset) > 1024 ||
345 get_unaligned_le16(&pSMB->t2_rsp.DataOffset) > 1024)
346 goto vt2_err;
347
Jeff Layton12df83c2011-01-20 13:36:51 -0500348 total_size = get_unaligned_le16(&pSMB->t2_rsp.ParameterCount);
349 if (total_size >= 512)
350 goto vt2_err;
351
Jeff Laytonfd5707e2011-03-31 17:22:07 -0400352 /* check that bcc is at least as big as parms + data, and that it is
353 * less than negotiated smb buffer
354 */
Jeff Layton12df83c2011-01-20 13:36:51 -0500355 total_size += get_unaligned_le16(&pSMB->t2_rsp.DataCount);
356 if (total_size > get_bcc(&pSMB->hdr) ||
357 total_size >= CIFSMaxBufSize + MAX_CIFS_HDR_SIZE)
358 goto vt2_err;
359
360 return 0;
361vt2_err:
Steve French50c2f752007-07-13 00:33:32 +0000362 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 sizeof(struct smb_t2_rsp) + 16);
Jeff Layton12df83c2011-01-20 13:36:51 -0500364 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365}
Jeff Layton690c5222011-01-20 13:36:51 -0500366
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000367static inline void inc_rfc1001_len(void *pSMB, int count)
368{
369 struct smb_hdr *hdr = (struct smb_hdr *)pSMB;
370
371 be32_add_cpu(&hdr->smb_buf_length, count);
372}
373
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374int
Steve French96daf2b2011-05-27 04:34:02 +0000375CIFSSMBNegotiate(unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376{
377 NEGOTIATE_REQ *pSMB;
378 NEGOTIATE_RSP *pSMBr;
379 int rc = 0;
380 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000381 int i;
Steve French50c2f752007-07-13 00:33:32 +0000382 struct TCP_Server_Info *server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 u16 count;
Steve French750d1152006-06-27 06:28:30 +0000384 unsigned int secFlags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385
Steve French790fe572007-07-07 19:25:05 +0000386 if (ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387 server = ses->server;
388 else {
389 rc = -EIO;
390 return rc;
391 }
392 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
393 (void **) &pSMB, (void **) &pSMBr);
394 if (rc)
395 return rc;
Steve French750d1152006-06-27 06:28:30 +0000396
397 /* if any of auth flags (ie not sign or seal) are overriden use them */
Steve French790fe572007-07-07 19:25:05 +0000398 if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
Steve French762e5ab2007-06-28 18:41:42 +0000399 secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
Steve French750d1152006-06-27 06:28:30 +0000400 else /* if override flags set only sign/seal OR them with global auth */
Jeff Layton04912d62010-04-24 07:57:45 -0400401 secFlags = global_secflags | ses->overrideSecFlg;
Steve French750d1152006-06-27 06:28:30 +0000402
Joe Perchesb6b38f72010-04-21 03:50:45 +0000403 cFYI(1, "secFlags 0x%x", secFlags);
Steve Frenchf40c5622006-06-28 00:13:38 +0000404
Steve French1982c342005-08-17 12:38:22 -0700405 pSMB->hdr.Mid = GetNextMid(server);
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000406 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
Steve Frencha0136892007-10-04 20:05:09 +0000407
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000408 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
Steve French254e55e2006-06-04 05:53:15 +0000409 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Steve Frencha0136892007-10-04 20:05:09 +0000410 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000411 cFYI(1, "Kerberos only mechanism, enable extended security");
Steve Frencha0136892007-10-04 20:05:09 +0000412 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Jeff Laytonb4d6fcf2011-01-07 11:30:28 -0500413 } else if ((secFlags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP)
Steve Frenchac683922009-05-06 04:16:04 +0000414 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
415 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_NTLMSSP) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000416 cFYI(1, "NTLMSSP only mechanism, enable extended security");
Steve Frenchac683922009-05-06 04:16:04 +0000417 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
418 }
Steve French50c2f752007-07-13 00:33:32 +0000419
Steve French39798772006-05-31 22:40:51 +0000420 count = 0;
Steve French50c2f752007-07-13 00:33:32 +0000421 for (i = 0; i < CIFS_NUM_PROT; i++) {
Steve French39798772006-05-31 22:40:51 +0000422 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
423 count += strlen(protocols[i].name) + 1;
424 /* null at end of source and target buffers anyway */
425 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000426 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 pSMB->ByteCount = cpu_to_le16(count);
428
429 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
430 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French50c2f752007-07-13 00:33:32 +0000431 if (rc != 0)
Steve French254e55e2006-06-04 05:53:15 +0000432 goto neg_err_exit;
433
Jeff Layton9bf67e52010-04-24 07:57:46 -0400434 server->dialect = le16_to_cpu(pSMBr->DialectIndex);
435 cFYI(1, "Dialect: %d", server->dialect);
Steve French254e55e2006-06-04 05:53:15 +0000436 /* Check wct = 1 error case */
Jeff Layton9bf67e52010-04-24 07:57:46 -0400437 if ((pSMBr->hdr.WordCount < 13) || (server->dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000438 /* core returns wct = 1, but we do not ask for core - otherwise
Steve French50c2f752007-07-13 00:33:32 +0000439 small wct just comes when dialect index is -1 indicating we
Steve French254e55e2006-06-04 05:53:15 +0000440 could not negotiate a common dialect */
441 rc = -EOPNOTSUPP;
442 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000443#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French790fe572007-07-07 19:25:05 +0000444 } else if ((pSMBr->hdr.WordCount == 13)
Jeff Layton9bf67e52010-04-24 07:57:46 -0400445 && ((server->dialect == LANMAN_PROT)
446 || (server->dialect == LANMAN2_PROT))) {
Steve Frenchb815f1e2006-10-02 05:53:29 +0000447 __s16 tmp;
Steve French50c2f752007-07-13 00:33:32 +0000448 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
Steve French254e55e2006-06-04 05:53:15 +0000449
Steve French790fe572007-07-07 19:25:05 +0000450 if ((secFlags & CIFSSEC_MAY_LANMAN) ||
Steve French750d1152006-06-27 06:28:30 +0000451 (secFlags & CIFSSEC_MAY_PLNTXT))
Steve French254e55e2006-06-04 05:53:15 +0000452 server->secType = LANMAN;
453 else {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000454 cERROR(1, "mount failed weak security disabled"
455 " in /proc/fs/cifs/SecurityFlags");
Steve French39798772006-05-31 22:40:51 +0000456 rc = -EOPNOTSUPP;
457 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000458 }
Steve French96daf2b2011-05-27 04:34:02 +0000459 server->sec_mode = (__u8)le16_to_cpu(rsp->SecurityMode);
Pavel Shilovsky10b9b982012-03-20 12:55:09 +0300460 server->maxReq = min_t(unsigned int,
461 le16_to_cpu(rsp->MaxMpxCount),
462 cifs_max_pending);
Pavel Shilovsky2d86dbc2012-02-06 15:59:18 +0400463 cifs_set_credits(server, server->maxReq);
Jeff Laytonc974bef2011-10-11 06:41:32 -0400464 server->maxBuf = le16_to_cpu(rsp->MaxBufSize);
Steve Frencheca6acf2009-02-20 05:43:09 +0000465 server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
Steve French254e55e2006-06-04 05:53:15 +0000466 /* even though we do not use raw we might as well set this
467 accurately, in case we ever find a need for it */
Steve French790fe572007-07-07 19:25:05 +0000468 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
Steve Frencheca6acf2009-02-20 05:43:09 +0000469 server->max_rw = 0xFF00;
Steve French254e55e2006-06-04 05:53:15 +0000470 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
471 } else {
Steve Frencheca6acf2009-02-20 05:43:09 +0000472 server->max_rw = 0;/* do not need to use raw anyway */
Steve French254e55e2006-06-04 05:53:15 +0000473 server->capabilities = CAP_MPX_MODE;
474 }
Steve Frenchb815f1e2006-10-02 05:53:29 +0000475 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
Steve French1a70d652006-10-02 05:59:18 +0000476 if (tmp == -1) {
Steve French25ee4a92006-09-30 00:54:23 +0000477 /* OS/2 often does not set timezone therefore
478 * we must use server time to calc time zone.
Steve Frenchb815f1e2006-10-02 05:53:29 +0000479 * Could deviate slightly from the right zone.
480 * Smallest defined timezone difference is 15 minutes
481 * (i.e. Nepal). Rounding up/down is done to match
482 * this requirement.
Steve French25ee4a92006-09-30 00:54:23 +0000483 */
Steve Frenchb815f1e2006-10-02 05:53:29 +0000484 int val, seconds, remain, result;
Steve French25ee4a92006-09-30 00:54:23 +0000485 struct timespec ts, utc;
486 utc = CURRENT_TIME;
Jeff Laytonc4a2c082009-05-27 09:37:33 -0400487 ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
488 rsp->SrvTime.Time, 0);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000489 cFYI(1, "SrvTime %d sec since 1970 (utc: %d) diff: %d",
Steve French50c2f752007-07-13 00:33:32 +0000490 (int)ts.tv_sec, (int)utc.tv_sec,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000491 (int)(utc.tv_sec - ts.tv_sec));
Steve Frenchb815f1e2006-10-02 05:53:29 +0000492 val = (int)(utc.tv_sec - ts.tv_sec);
Andre Haupt8594c152007-08-30 20:18:41 +0000493 seconds = abs(val);
Steve French947a5062006-10-02 05:55:25 +0000494 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
Steve Frenchb815f1e2006-10-02 05:53:29 +0000495 remain = seconds % MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000496 if (remain >= (MIN_TZ_ADJ / 2))
Steve Frenchb815f1e2006-10-02 05:53:29 +0000497 result += MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000498 if (val < 0)
Steve Frenchad7a2922008-02-07 23:25:02 +0000499 result = -result;
Steve Frenchb815f1e2006-10-02 05:53:29 +0000500 server->timeAdj = result;
Steve French25ee4a92006-09-30 00:54:23 +0000501 } else {
Steve Frenchb815f1e2006-10-02 05:53:29 +0000502 server->timeAdj = (int)tmp;
503 server->timeAdj *= 60; /* also in seconds */
Steve French25ee4a92006-09-30 00:54:23 +0000504 }
Joe Perchesb6b38f72010-04-21 03:50:45 +0000505 cFYI(1, "server->timeAdj: %d seconds", server->timeAdj);
Steve French25ee4a92006-09-30 00:54:23 +0000506
Steve French39798772006-05-31 22:40:51 +0000507
Steve French254e55e2006-06-04 05:53:15 +0000508 /* BB get server time for time conversions and add
Steve French50c2f752007-07-13 00:33:32 +0000509 code to use it and timezone since this is not UTC */
Steve French39798772006-05-31 22:40:51 +0000510
Steve French50c2f752007-07-13 00:33:32 +0000511 if (rsp->EncryptionKeyLength ==
Steve French25ee4a92006-09-30 00:54:23 +0000512 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500513 memcpy(ses->server->cryptkey, rsp->EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000514 CIFS_CRYPTO_KEY_SIZE);
Steve French96daf2b2011-05-27 04:34:02 +0000515 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
Steve French254e55e2006-06-04 05:53:15 +0000516 rc = -EIO; /* need cryptkey unless plain text */
517 goto neg_err_exit;
518 }
Steve French39798772006-05-31 22:40:51 +0000519
Steve Frenchf19159d2010-04-21 04:12:10 +0000520 cFYI(1, "LANMAN negotiated");
Steve French254e55e2006-06-04 05:53:15 +0000521 /* we will not end up setting signing flags - as no signing
522 was in LANMAN and server did not return the flags on */
523 goto signing_check;
Steve French7c7b25b2006-06-01 19:20:10 +0000524#else /* weak security disabled */
Steve French790fe572007-07-07 19:25:05 +0000525 } else if (pSMBr->hdr.WordCount == 13) {
Steve Frenchf19159d2010-04-21 04:12:10 +0000526 cERROR(1, "mount failed, cifs module not built "
527 "with CIFS_WEAK_PW_HASH support");
Dan Carpenter8212cf72010-03-15 11:22:26 +0300528 rc = -EOPNOTSUPP;
Steve French7c7b25b2006-06-01 19:20:10 +0000529#endif /* WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000530 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000531 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000532 /* unknown wct */
533 rc = -EOPNOTSUPP;
534 goto neg_err_exit;
535 }
536 /* else wct == 17 NTLM */
Steve French96daf2b2011-05-27 04:34:02 +0000537 server->sec_mode = pSMBr->SecurityMode;
538 if ((server->sec_mode & SECMODE_USER) == 0)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000539 cFYI(1, "share mode security");
Steve French39798772006-05-31 22:40:51 +0000540
Steve French96daf2b2011-05-27 04:34:02 +0000541 if ((server->sec_mode & SECMODE_PW_ENCRYPT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000542#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French750d1152006-06-27 06:28:30 +0000543 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000544#endif /* CIFS_WEAK_PW_HASH */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000545 cERROR(1, "Server requests plain text password"
546 " but client support disabled");
Steve French9312f672006-06-04 22:21:07 +0000547
Steve French790fe572007-07-07 19:25:05 +0000548 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
Steve French254e55e2006-06-04 05:53:15 +0000549 server->secType = NTLMv2;
Steve French790fe572007-07-07 19:25:05 +0000550 else if (secFlags & CIFSSEC_MAY_NTLM)
Steve French254e55e2006-06-04 05:53:15 +0000551 server->secType = NTLM;
Steve French790fe572007-07-07 19:25:05 +0000552 else if (secFlags & CIFSSEC_MAY_NTLMV2)
Steve Frenchf40c5622006-06-28 00:13:38 +0000553 server->secType = NTLMv2;
Steve Frencha0136892007-10-04 20:05:09 +0000554 else if (secFlags & CIFSSEC_MAY_KRB5)
555 server->secType = Kerberos;
Steve Frenchac683922009-05-06 04:16:04 +0000556 else if (secFlags & CIFSSEC_MAY_NTLMSSP)
Steve Frenchf46c7232009-06-25 03:04:20 +0000557 server->secType = RawNTLMSSP;
Steve Frencha0136892007-10-04 20:05:09 +0000558 else if (secFlags & CIFSSEC_MAY_LANMAN)
559 server->secType = LANMAN;
Steve Frencha0136892007-10-04 20:05:09 +0000560 else {
561 rc = -EOPNOTSUPP;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000562 cERROR(1, "Invalid security type");
Steve Frencha0136892007-10-04 20:05:09 +0000563 goto neg_err_exit;
564 }
565 /* else ... any others ...? */
Steve French7c7b25b2006-06-01 19:20:10 +0000566
Steve French254e55e2006-06-04 05:53:15 +0000567 /* one byte, so no need to convert this or EncryptionKeyLen from
568 little endian */
Pavel Shilovsky10b9b982012-03-20 12:55:09 +0300569 server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount),
570 cifs_max_pending);
Pavel Shilovsky2d86dbc2012-02-06 15:59:18 +0400571 cifs_set_credits(server, server->maxReq);
Steve French254e55e2006-06-04 05:53:15 +0000572 /* probably no need to store and check maxvcs */
Jeff Laytonc974bef2011-10-11 06:41:32 -0400573 server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize);
Steve Frencheca6acf2009-02-20 05:43:09 +0000574 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000575 cFYI(DBG2, "Max buf = %d", ses->server->maxBuf);
Steve French254e55e2006-06-04 05:53:15 +0000576 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e2006-10-02 05:53:29 +0000577 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
578 server->timeAdj *= 60;
Steve French254e55e2006-06-04 05:53:15 +0000579 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500580 memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000581 CIFS_CRYPTO_KEY_SIZE);
Steve French07cc6cf2011-05-27 04:12:29 +0000582 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC ||
583 server->capabilities & CAP_EXTENDED_SECURITY) &&
584 (pSMBr->EncryptionKeyLength == 0)) {
Steve French254e55e2006-06-04 05:53:15 +0000585 /* decode security blob */
Jeff Layton820a8032011-05-04 08:05:26 -0400586 count = get_bcc(&pSMBr->hdr);
Jeff Laytone187e442007-10-16 17:10:44 +0000587 if (count < 16) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588 rc = -EIO;
Jeff Laytone187e442007-10-16 17:10:44 +0000589 goto neg_err_exit;
590 }
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530591 spin_lock(&cifs_tcp_ses_lock);
Jeff Laytone7ddee92008-11-14 13:44:38 -0500592 if (server->srv_count > 1) {
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530593 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000594 if (memcmp(server->server_GUID,
595 pSMBr->u.extended_response.
596 GUID, 16) != 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000597 cFYI(1, "server UID changed");
Steve French254e55e2006-06-04 05:53:15 +0000598 memcpy(server->server_GUID,
Jeff Laytone187e442007-10-16 17:10:44 +0000599 pSMBr->u.extended_response.GUID,
600 16);
601 }
Jeff Laytone7ddee92008-11-14 13:44:38 -0500602 } else {
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530603 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000604 memcpy(server->server_GUID,
605 pSMBr->u.extended_response.GUID, 16);
Jeff Laytone7ddee92008-11-14 13:44:38 -0500606 }
Jeff Laytone187e442007-10-16 17:10:44 +0000607
608 if (count == 16) {
609 server->secType = RawNTLMSSP;
Steve French254e55e2006-06-04 05:53:15 +0000610 } else {
611 rc = decode_negTokenInit(pSMBr->u.extended_response.
Jeff Layton26efa0b2010-04-24 07:57:49 -0400612 SecurityBlob, count - 16,
613 server);
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000614 if (rc == 1)
Jeff Laytone5459372007-11-03 05:11:06 +0000615 rc = 0;
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000616 else
Steve French254e55e2006-06-04 05:53:15 +0000617 rc = -EINVAL;
Shirish Pargaonkar2b149f12010-09-18 22:02:18 -0500618 if (server->secType == Kerberos) {
619 if (!server->sec_kerberos &&
620 !server->sec_mskerberos)
621 rc = -EOPNOTSUPP;
622 } else if (server->secType == RawNTLMSSP) {
623 if (!server->sec_ntlmssp)
624 rc = -EOPNOTSUPP;
625 } else
626 rc = -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 }
Steve French96daf2b2011-05-27 04:34:02 +0000628 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
Steve French07cc6cf2011-05-27 04:12:29 +0000629 rc = -EIO; /* no crypt key only if plain text pwd */
630 goto neg_err_exit;
Steve French254e55e2006-06-04 05:53:15 +0000631 } else
632 server->capabilities &= ~CAP_EXTENDED_SECURITY;
633
Steve French6344a422006-06-12 04:18:35 +0000634#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French254e55e2006-06-04 05:53:15 +0000635signing_check:
Steve French6344a422006-06-12 04:18:35 +0000636#endif
Steve French762e5ab2007-06-28 18:41:42 +0000637 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
638 /* MUST_SIGN already includes the MAY_SIGN FLAG
639 so if this is zero it means that signing is disabled */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000640 cFYI(1, "Signing disabled");
Steve French96daf2b2011-05-27 04:34:02 +0000641 if (server->sec_mode & SECMODE_SIGN_REQUIRED) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000642 cERROR(1, "Server requires "
Jeff Layton7111d212007-10-16 16:50:25 +0000643 "packet signing to be enabled in "
Joe Perchesb6b38f72010-04-21 03:50:45 +0000644 "/proc/fs/cifs/SecurityFlags.");
Steve Frenchabb63d62007-10-18 02:58:40 +0000645 rc = -EOPNOTSUPP;
646 }
Steve French96daf2b2011-05-27 04:34:02 +0000647 server->sec_mode &=
Steve French254e55e2006-06-04 05:53:15 +0000648 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Steve French762e5ab2007-06-28 18:41:42 +0000649 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
650 /* signing required */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000651 cFYI(1, "Must sign - secFlags 0x%x", secFlags);
Steve French96daf2b2011-05-27 04:34:02 +0000652 if ((server->sec_mode &
Steve French762e5ab2007-06-28 18:41:42 +0000653 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000654 cERROR(1, "signing required but server lacks support");
Jeff38c10a12007-07-06 21:10:07 +0000655 rc = -EOPNOTSUPP;
Steve French762e5ab2007-06-28 18:41:42 +0000656 } else
Steve French96daf2b2011-05-27 04:34:02 +0000657 server->sec_mode |= SECMODE_SIGN_REQUIRED;
Steve French762e5ab2007-06-28 18:41:42 +0000658 } else {
659 /* signing optional ie CIFSSEC_MAY_SIGN */
Steve French96daf2b2011-05-27 04:34:02 +0000660 if ((server->sec_mode & SECMODE_SIGN_REQUIRED) == 0)
661 server->sec_mode &=
Steve French254e55e2006-06-04 05:53:15 +0000662 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 }
Steve French50c2f752007-07-13 00:33:32 +0000664
665neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700666 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000667
Joe Perchesb6b38f72010-04-21 03:50:45 +0000668 cFYI(1, "negprot rc %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 return rc;
670}
671
672int
Steve French96daf2b2011-05-27 04:34:02 +0000673CIFSSMBTDis(const int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674{
675 struct smb_hdr *smb_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677
Joe Perchesb6b38f72010-04-21 03:50:45 +0000678 cFYI(1, "In tree disconnect");
Jeff Laytonf1987b42008-11-15 11:12:47 -0500679
680 /* BB: do we need to check this? These should never be NULL. */
681 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
682 return -EIO;
683
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 /*
Jeff Laytonf1987b42008-11-15 11:12:47 -0500685 * No need to return error on this operation if tid invalidated and
686 * closed on server already e.g. due to tcp session crashing. Also,
687 * the tcon is no longer on the list, so no need to take lock before
688 * checking this.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 */
Steve French268875b2009-06-25 00:29:21 +0000690 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
Steve French50c2f752007-07-13 00:33:32 +0000691 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692
Steve French50c2f752007-07-13 00:33:32 +0000693 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700694 (void **)&smb_buffer);
Jeff Laytonf1987b42008-11-15 11:12:47 -0500695 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 return rc;
Steve French133672e2007-11-13 22:41:37 +0000697
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400698 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)smb_buffer, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000700 cFYI(1, "Tree disconnect failed %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701
Steve French50c2f752007-07-13 00:33:32 +0000702 /* No need to return error on this operation if tid invalidated and
Jeff Laytonf1987b42008-11-15 11:12:47 -0500703 closed on server already e.g. due to tcp session crashing */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 if (rc == -EAGAIN)
705 rc = 0;
706
707 return rc;
708}
709
Jeff Layton766fdbb2011-01-11 07:24:21 -0500710/*
711 * This is a no-op for now. We're not really interested in the reply, but
712 * rather in the fact that the server sent one and that server->lstrp
713 * gets updated.
714 *
715 * FIXME: maybe we should consider checking that the reply matches request?
716 */
717static void
718cifs_echo_callback(struct mid_q_entry *mid)
719{
720 struct TCP_Server_Info *server = mid->callback_data;
721
722 DeleteMidQEntry(mid);
Pavel Shilovsky2d86dbc2012-02-06 15:59:18 +0400723 cifs_add_credits(server, 1);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500724}
725
726int
727CIFSSMBEcho(struct TCP_Server_Info *server)
728{
729 ECHO_REQ *smb;
730 int rc = 0;
Jeff Laytonfcc31cb2011-05-19 16:22:53 -0400731 struct kvec iov;
Jeff Layton766fdbb2011-01-11 07:24:21 -0500732
733 cFYI(1, "In echo request");
734
735 rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
736 if (rc)
737 return rc;
738
739 /* set up echo request */
Steve French5443d132011-03-13 05:08:25 +0000740 smb->hdr.Tid = 0xffff;
Jeff Layton99d86c82011-01-20 21:19:25 -0500741 smb->hdr.WordCount = 1;
742 put_unaligned_le16(1, &smb->EchoCount);
Jeff Layton820a8032011-05-04 08:05:26 -0400743 put_bcc(1, &smb->hdr);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500744 smb->Data[0] = 'a';
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000745 inc_rfc1001_len(smb, 3);
Jeff Laytonfcc31cb2011-05-19 16:22:53 -0400746 iov.iov_base = smb;
747 iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
Jeff Layton766fdbb2011-01-11 07:24:21 -0500748
Jeff Layton44d22d82011-10-19 15:29:49 -0400749 rc = cifs_call_async(server, &iov, 1, NULL, cifs_echo_callback,
750 server, true);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500751 if (rc)
752 cFYI(1, "Echo request failed: %d", rc);
753
754 cifs_small_buf_release(smb);
755
756 return rc;
757}
758
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759int
Steve French96daf2b2011-05-27 04:34:02 +0000760CIFSSMBLogoff(const int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 LOGOFF_ANDX_REQ *pSMB;
763 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764
Joe Perchesb6b38f72010-04-21 03:50:45 +0000765 cFYI(1, "In SMBLogoff for session disconnect");
Jeff Layton14fbf502008-11-14 13:53:46 -0500766
767 /*
768 * BB: do we need to check validity of ses and server? They should
769 * always be valid since we have an active reference. If not, that
770 * should probably be a BUG()
771 */
772 if (!ses || !ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 return -EIO;
774
Steve Frenchd7b619c2010-02-25 05:36:46 +0000775 mutex_lock(&ses->session_mutex);
Steve French3b795212008-11-13 19:45:32 +0000776 if (ses->need_reconnect)
777 goto session_already_dead; /* no need to send SMBlogoff if uid
778 already closed due to reconnect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
780 if (rc) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000781 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 return rc;
783 }
784
Steve French3b795212008-11-13 19:45:32 +0000785 pSMB->hdr.Mid = GetNextMid(ses->server);
Steve French1982c342005-08-17 12:38:22 -0700786
Steve French96daf2b2011-05-27 04:34:02 +0000787 if (ses->server->sec_mode &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
789 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790
791 pSMB->hdr.Uid = ses->Suid;
792
793 pSMB->AndXCommand = 0xFF;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400794 rc = SendReceiveNoRsp(xid, ses, (char *) pSMB, 0);
Steve French3b795212008-11-13 19:45:32 +0000795session_already_dead:
Steve Frenchd7b619c2010-02-25 05:36:46 +0000796 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797
798 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000799 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800 error */
801 if (rc == -EAGAIN)
802 rc = 0;
803 return rc;
804}
805
806int
Steve French96daf2b2011-05-27 04:34:02 +0000807CIFSPOSIXDelFile(const int xid, struct cifs_tcon *tcon, const char *fileName,
Steve French2d785a52007-07-15 01:48:57 +0000808 __u16 type, const struct nls_table *nls_codepage, int remap)
809{
810 TRANSACTION2_SPI_REQ *pSMB = NULL;
811 TRANSACTION2_SPI_RSP *pSMBr = NULL;
812 struct unlink_psx_rq *pRqD;
813 int name_len;
814 int rc = 0;
815 int bytes_returned = 0;
816 __u16 params, param_offset, offset, byte_count;
817
Joe Perchesb6b38f72010-04-21 03:50:45 +0000818 cFYI(1, "In POSIX delete");
Steve French2d785a52007-07-15 01:48:57 +0000819PsxDelete:
820 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
821 (void **) &pSMBr);
822 if (rc)
823 return rc;
824
825 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
826 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -0600827 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
828 PATH_MAX, nls_codepage, remap);
Steve French2d785a52007-07-15 01:48:57 +0000829 name_len++; /* trailing null */
830 name_len *= 2;
831 } else { /* BB add path length overrun check */
832 name_len = strnlen(fileName, PATH_MAX);
833 name_len++; /* trailing null */
834 strncpy(pSMB->FileName, fileName, name_len);
835 }
836
837 params = 6 + name_len;
838 pSMB->MaxParameterCount = cpu_to_le16(2);
839 pSMB->MaxDataCount = 0; /* BB double check this with jra */
840 pSMB->MaxSetupCount = 0;
841 pSMB->Reserved = 0;
842 pSMB->Flags = 0;
843 pSMB->Timeout = 0;
844 pSMB->Reserved2 = 0;
845 param_offset = offsetof(struct smb_com_transaction2_spi_req,
846 InformationLevel) - 4;
847 offset = param_offset + params;
848
849 /* Setup pointer to Request Data (inode type) */
850 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
851 pRqD->type = cpu_to_le16(type);
852 pSMB->ParameterOffset = cpu_to_le16(param_offset);
853 pSMB->DataOffset = cpu_to_le16(offset);
854 pSMB->SetupCount = 1;
855 pSMB->Reserved3 = 0;
856 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
857 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
858
859 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
860 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
861 pSMB->ParameterCount = cpu_to_le16(params);
862 pSMB->TotalParameterCount = pSMB->ParameterCount;
863 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
864 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000865 inc_rfc1001_len(pSMB, byte_count);
Steve French2d785a52007-07-15 01:48:57 +0000866 pSMB->ByteCount = cpu_to_le16(byte_count);
867 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
868 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000869 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000870 cFYI(1, "Posix delete returned %d", rc);
Steve French2d785a52007-07-15 01:48:57 +0000871 cifs_buf_release(pSMB);
872
873 cifs_stats_inc(&tcon->num_deletes);
874
875 if (rc == -EAGAIN)
876 goto PsxDelete;
877
878 return rc;
879}
880
881int
Steve French96daf2b2011-05-27 04:34:02 +0000882CIFSSMBDelFile(const int xid, struct cifs_tcon *tcon, const char *fileName,
Steve French737b7582005-04-28 22:41:06 -0700883 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884{
885 DELETE_FILE_REQ *pSMB = NULL;
886 DELETE_FILE_RSP *pSMBr = NULL;
887 int rc = 0;
888 int bytes_returned;
889 int name_len;
890
891DelFileRetry:
892 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
893 (void **) &pSMBr);
894 if (rc)
895 return rc;
896
897 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
898 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -0600899 cifsConvertToUTF16((__le16 *) pSMB->fileName, fileName,
900 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 name_len++; /* trailing null */
902 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700903 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904 name_len = strnlen(fileName, PATH_MAX);
905 name_len++; /* trailing null */
906 strncpy(pSMB->fileName, fileName, name_len);
907 }
908 pSMB->SearchAttributes =
909 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
910 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000911 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 pSMB->ByteCount = cpu_to_le16(name_len + 1);
913 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
914 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700915 cifs_stats_inc(&tcon->num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000916 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000917 cFYI(1, "Error in RMFile = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918
919 cifs_buf_release(pSMB);
920 if (rc == -EAGAIN)
921 goto DelFileRetry;
922
923 return rc;
924}
925
926int
Steve French96daf2b2011-05-27 04:34:02 +0000927CIFSSMBRmDir(const int xid, struct cifs_tcon *tcon, const char *dirName,
Steve French737b7582005-04-28 22:41:06 -0700928 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929{
930 DELETE_DIRECTORY_REQ *pSMB = NULL;
931 DELETE_DIRECTORY_RSP *pSMBr = NULL;
932 int rc = 0;
933 int bytes_returned;
934 int name_len;
935
Joe Perchesb6b38f72010-04-21 03:50:45 +0000936 cFYI(1, "In CIFSSMBRmDir");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937RmDirRetry:
938 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
939 (void **) &pSMBr);
940 if (rc)
941 return rc;
942
943 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -0600944 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, dirName,
945 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946 name_len++; /* trailing null */
947 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700948 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949 name_len = strnlen(dirName, PATH_MAX);
950 name_len++; /* trailing null */
951 strncpy(pSMB->DirName, dirName, name_len);
952 }
953
954 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000955 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956 pSMB->ByteCount = cpu_to_le16(name_len + 1);
957 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
958 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700959 cifs_stats_inc(&tcon->num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000960 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000961 cFYI(1, "Error in RMDir = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962
963 cifs_buf_release(pSMB);
964 if (rc == -EAGAIN)
965 goto RmDirRetry;
966 return rc;
967}
968
969int
Steve French96daf2b2011-05-27 04:34:02 +0000970CIFSSMBMkDir(const int xid, struct cifs_tcon *tcon,
Steve French737b7582005-04-28 22:41:06 -0700971 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972{
973 int rc = 0;
974 CREATE_DIRECTORY_REQ *pSMB = NULL;
975 CREATE_DIRECTORY_RSP *pSMBr = NULL;
976 int bytes_returned;
977 int name_len;
978
Joe Perchesb6b38f72010-04-21 03:50:45 +0000979 cFYI(1, "In CIFSSMBMkDir");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980MkDirRetry:
981 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
982 (void **) &pSMBr);
983 if (rc)
984 return rc;
985
986 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -0600987 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
988 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989 name_len++; /* trailing null */
990 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700991 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 name_len = strnlen(name, PATH_MAX);
993 name_len++; /* trailing null */
994 strncpy(pSMB->DirName, name, name_len);
995 }
996
997 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000998 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999 pSMB->ByteCount = cpu_to_le16(name_len + 1);
1000 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1001 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001002 cifs_stats_inc(&tcon->num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +00001003 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001004 cFYI(1, "Error in Mkdir = %d", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07001005
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006 cifs_buf_release(pSMB);
1007 if (rc == -EAGAIN)
1008 goto MkDirRetry;
1009 return rc;
1010}
1011
Steve French2dd29d32007-04-23 22:07:35 +00001012int
Steve French96daf2b2011-05-27 04:34:02 +00001013CIFSPOSIXCreate(const int xid, struct cifs_tcon *tcon, __u32 posix_flags,
Steve Frenchad7a2922008-02-07 23:25:02 +00001014 __u64 mode, __u16 *netfid, FILE_UNIX_BASIC_INFO *pRetData,
Steve French50c2f752007-07-13 00:33:32 +00001015 __u32 *pOplock, const char *name,
Steve French2dd29d32007-04-23 22:07:35 +00001016 const struct nls_table *nls_codepage, int remap)
1017{
1018 TRANSACTION2_SPI_REQ *pSMB = NULL;
1019 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1020 int name_len;
1021 int rc = 0;
1022 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001023 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +00001024 OPEN_PSX_REQ *pdata;
1025 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +00001026
Joe Perchesb6b38f72010-04-21 03:50:45 +00001027 cFYI(1, "In POSIX Create");
Steve French2dd29d32007-04-23 22:07:35 +00001028PsxCreat:
1029 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1030 (void **) &pSMBr);
1031 if (rc)
1032 return rc;
1033
1034 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1035 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001036 cifsConvertToUTF16((__le16 *) pSMB->FileName, name,
1037 PATH_MAX, nls_codepage, remap);
Steve French2dd29d32007-04-23 22:07:35 +00001038 name_len++; /* trailing null */
1039 name_len *= 2;
1040 } else { /* BB improve the check for buffer overruns BB */
1041 name_len = strnlen(name, PATH_MAX);
1042 name_len++; /* trailing null */
1043 strncpy(pSMB->FileName, name, name_len);
1044 }
1045
1046 params = 6 + name_len;
1047 count = sizeof(OPEN_PSX_REQ);
1048 pSMB->MaxParameterCount = cpu_to_le16(2);
1049 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1050 pSMB->MaxSetupCount = 0;
1051 pSMB->Reserved = 0;
1052 pSMB->Flags = 0;
1053 pSMB->Timeout = 0;
1054 pSMB->Reserved2 = 0;
1055 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001056 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001057 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001058 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001059 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001060 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001061 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001062 pdata->OpenFlags = cpu_to_le32(*pOplock);
1063 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1064 pSMB->DataOffset = cpu_to_le16(offset);
1065 pSMB->SetupCount = 1;
1066 pSMB->Reserved3 = 0;
1067 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1068 byte_count = 3 /* pad */ + params + count;
1069
1070 pSMB->DataCount = cpu_to_le16(count);
1071 pSMB->ParameterCount = cpu_to_le16(params);
1072 pSMB->TotalDataCount = pSMB->DataCount;
1073 pSMB->TotalParameterCount = pSMB->ParameterCount;
1074 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1075 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001076 inc_rfc1001_len(pSMB, byte_count);
Steve French2dd29d32007-04-23 22:07:35 +00001077 pSMB->ByteCount = cpu_to_le16(byte_count);
1078 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1079 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1080 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001081 cFYI(1, "Posix create returned %d", rc);
Steve French2dd29d32007-04-23 22:07:35 +00001082 goto psx_create_err;
1083 }
1084
Joe Perchesb6b38f72010-04-21 03:50:45 +00001085 cFYI(1, "copying inode info");
Steve French2dd29d32007-04-23 22:07:35 +00001086 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1087
Jeff Layton820a8032011-05-04 08:05:26 -04001088 if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) {
Steve French2dd29d32007-04-23 22:07:35 +00001089 rc = -EIO; /* bad smb */
1090 goto psx_create_err;
1091 }
1092
1093 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001094 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001095 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001096
Steve French2dd29d32007-04-23 22:07:35 +00001097 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001098 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001099 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1100 /* Let caller know file was created so we can set the mode. */
1101 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001102 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001103 *pOplock |= CIFS_CREATE_ACTION;
1104 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001105 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1106 pRetData->Type = cpu_to_le32(-1); /* unknown */
Joe Perchesb6b38f72010-04-21 03:50:45 +00001107 cFYI(DBG2, "unknown type");
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001108 } else {
Jeff Layton820a8032011-05-04 08:05:26 -04001109 if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001110 + sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001111 cERROR(1, "Open response data too small");
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001112 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001113 goto psx_create_err;
1114 }
Steve French50c2f752007-07-13 00:33:32 +00001115 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001116 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001117 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001118 }
Steve French2dd29d32007-04-23 22:07:35 +00001119
1120psx_create_err:
1121 cifs_buf_release(pSMB);
1122
Steve French65bc98b2009-07-10 15:27:25 +00001123 if (posix_flags & SMB_O_DIRECTORY)
1124 cifs_stats_inc(&tcon->num_posixmkdirs);
1125 else
1126 cifs_stats_inc(&tcon->num_posixopens);
Steve French2dd29d32007-04-23 22:07:35 +00001127
1128 if (rc == -EAGAIN)
1129 goto PsxCreat;
1130
Steve French50c2f752007-07-13 00:33:32 +00001131 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001132}
1133
Steve Frencha9d02ad2005-08-24 23:06:05 -07001134static __u16 convert_disposition(int disposition)
1135{
1136 __u16 ofun = 0;
1137
1138 switch (disposition) {
1139 case FILE_SUPERSEDE:
1140 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1141 break;
1142 case FILE_OPEN:
1143 ofun = SMBOPEN_OAPPEND;
1144 break;
1145 case FILE_CREATE:
1146 ofun = SMBOPEN_OCREATE;
1147 break;
1148 case FILE_OPEN_IF:
1149 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1150 break;
1151 case FILE_OVERWRITE:
1152 ofun = SMBOPEN_OTRUNC;
1153 break;
1154 case FILE_OVERWRITE_IF:
1155 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1156 break;
1157 default:
Joe Perchesb6b38f72010-04-21 03:50:45 +00001158 cFYI(1, "unknown disposition %d", disposition);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001159 ofun = SMBOPEN_OAPPEND; /* regular open */
1160 }
1161 return ofun;
1162}
1163
Jeff Layton35fc37d2008-05-14 10:22:03 -07001164static int
1165access_flags_to_smbopen_mode(const int access_flags)
1166{
1167 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1168
1169 if (masked_flags == GENERIC_READ)
1170 return SMBOPEN_READ;
1171 else if (masked_flags == GENERIC_WRITE)
1172 return SMBOPEN_WRITE;
1173
1174 /* just go for read/write */
1175 return SMBOPEN_READWRITE;
1176}
1177
Steve Frencha9d02ad2005-08-24 23:06:05 -07001178int
Steve French96daf2b2011-05-27 04:34:02 +00001179SMBLegacyOpen(const int xid, struct cifs_tcon *tcon,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001180 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001181 const int access_flags, const int create_options, __u16 *netfid,
1182 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001183 const struct nls_table *nls_codepage, int remap)
1184{
1185 int rc = -EACCES;
1186 OPENX_REQ *pSMB = NULL;
1187 OPENX_RSP *pSMBr = NULL;
1188 int bytes_returned;
1189 int name_len;
1190 __u16 count;
1191
1192OldOpenRetry:
1193 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1194 (void **) &pSMBr);
1195 if (rc)
1196 return rc;
1197
1198 pSMB->AndXCommand = 0xFF; /* none */
1199
1200 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1201 count = 1; /* account for one byte pad to word boundary */
1202 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001203 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1204 fileName, PATH_MAX, nls_codepage, remap);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001205 name_len++; /* trailing null */
1206 name_len *= 2;
1207 } else { /* BB improve check for buffer overruns BB */
1208 count = 0; /* no pad */
1209 name_len = strnlen(fileName, PATH_MAX);
1210 name_len++; /* trailing null */
1211 strncpy(pSMB->fileName, fileName, name_len);
1212 }
1213 if (*pOplock & REQ_OPLOCK)
1214 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001215 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001216 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001217
Steve Frencha9d02ad2005-08-24 23:06:05 -07001218 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001219 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001220 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1221 /* set file as system file if special file such
1222 as fifo and server expecting SFU style and
1223 no Unix extensions */
1224
Steve French790fe572007-07-07 19:25:05 +00001225 if (create_options & CREATE_OPTION_SPECIAL)
1226 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001227 else /* BB FIXME BB */
1228 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001229
Jeff Layton67750fb2008-05-09 22:28:02 +00001230 if (create_options & CREATE_OPTION_READONLY)
1231 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001232
1233 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001234/* pSMB->CreateOptions = cpu_to_le32(create_options &
1235 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001236 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001237
1238 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001239 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001240 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001241 inc_rfc1001_len(pSMB, count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001242
1243 pSMB->ByteCount = cpu_to_le16(count);
1244 /* long_op set to 1 to allow for oplock break timeouts */
1245 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001246 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001247 cifs_stats_inc(&tcon->num_opens);
1248 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001249 cFYI(1, "Error in Open = %d", rc);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001250 } else {
1251 /* BB verify if wct == 15 */
1252
Steve French582d21e2008-05-13 04:54:12 +00001253/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001254
1255 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1256 /* Let caller know file was created so we can set the mode. */
1257 /* Do we care about the CreateAction in any other cases? */
1258 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001259/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001260 *pOplock |= CIFS_CREATE_ACTION; */
1261 /* BB FIXME END */
1262
Steve French790fe572007-07-07 19:25:05 +00001263 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001264 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1265 pfile_info->LastAccessTime = 0; /* BB fixme */
1266 pfile_info->LastWriteTime = 0; /* BB fixme */
1267 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001268 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001269 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001270 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001271 pfile_info->AllocationSize =
1272 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1273 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001274 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001275 pfile_info->DeletePending = 0;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001276 }
1277 }
1278
1279 cifs_buf_release(pSMB);
1280 if (rc == -EAGAIN)
1281 goto OldOpenRetry;
1282 return rc;
1283}
1284
Linus Torvalds1da177e2005-04-16 15:20:36 -07001285int
Steve French96daf2b2011-05-27 04:34:02 +00001286CIFSSMBOpen(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001288 const int access_flags, const int create_options, __u16 *netfid,
1289 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001290 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001291{
1292 int rc = -EACCES;
1293 OPEN_REQ *pSMB = NULL;
1294 OPEN_RSP *pSMBr = NULL;
1295 int bytes_returned;
1296 int name_len;
1297 __u16 count;
1298
1299openRetry:
1300 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1301 (void **) &pSMBr);
1302 if (rc)
1303 return rc;
1304
1305 pSMB->AndXCommand = 0xFF; /* none */
1306
1307 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1308 count = 1; /* account for one byte pad to word boundary */
1309 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001310 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1311 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312 name_len++; /* trailing null */
1313 name_len *= 2;
1314 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001315 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 count = 0; /* no pad */
1317 name_len = strnlen(fileName, PATH_MAX);
1318 name_len++; /* trailing null */
1319 pSMB->NameLength = cpu_to_le16(name_len);
1320 strncpy(pSMB->fileName, fileName, name_len);
1321 }
1322 if (*pOplock & REQ_OPLOCK)
1323 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001324 else if (*pOplock & REQ_BATCHOPLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1327 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -07001328 /* set file as system file if special file such
1329 as fifo and server expecting SFU style and
1330 no Unix extensions */
Steve French790fe572007-07-07 19:25:05 +00001331 if (create_options & CREATE_OPTION_SPECIAL)
Steve Frencheda3c0292005-07-21 15:20:28 -07001332 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1333 else
1334 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Jeff Layton67750fb2008-05-09 22:28:02 +00001335
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336 /* XP does not handle ATTR_POSIX_SEMANTICS */
1337 /* but it helps speed up case sensitive checks for other
1338 servers such as Samba */
1339 if (tcon->ses->capabilities & CAP_UNIX)
1340 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1341
Jeff Layton67750fb2008-05-09 22:28:02 +00001342 if (create_options & CREATE_OPTION_READONLY)
1343 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1344
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1346 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -07001347 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001348 /* BB Expirement with various impersonation levels and verify */
1349 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350 pSMB->SecurityFlags =
1351 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1352
1353 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001354 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355
1356 pSMB->ByteCount = cpu_to_le16(count);
1357 /* long_op set to 1 to allow for oplock break timeouts */
1358 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001359 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001360 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001362 cFYI(1, "Error in Open = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363 } else {
Steve French09d1db52005-04-28 22:41:08 -07001364 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1366 /* Let caller know file was created so we can set the mode. */
1367 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001368 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve French50c2f752007-07-13 00:33:32 +00001369 *pOplock |= CIFS_CREATE_ACTION;
Steve French790fe572007-07-07 19:25:05 +00001370 if (pfile_info) {
Steve French61e74802008-12-03 00:57:54 +00001371 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1372 36 /* CreationTime to Attributes */);
1373 /* the file_info buf is endian converted by caller */
1374 pfile_info->AllocationSize = pSMBr->AllocationSize;
1375 pfile_info->EndOfFile = pSMBr->EndOfFile;
1376 pfile_info->NumberOfLinks = cpu_to_le32(1);
1377 pfile_info->DeletePending = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001380
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381 cifs_buf_release(pSMB);
1382 if (rc == -EAGAIN)
1383 goto openRetry;
1384 return rc;
1385}
1386
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001387/*
1388 * Discard any remaining data in the current SMB. To do this, we borrow the
1389 * current bigbuf.
1390 */
1391static int
1392cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1393{
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001394 unsigned int rfclen = get_rfc1002_length(server->smallbuf);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001395 int remaining = rfclen + 4 - server->total_read;
1396 struct cifs_readdata *rdata = mid->callback_data;
1397
1398 while (remaining > 0) {
1399 int length;
1400
1401 length = cifs_read_from_socket(server, server->bigbuf,
1402 min_t(unsigned int, remaining,
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001403 CIFSMaxBufSize + MAX_HEADER_SIZE(server)));
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001404 if (length < 0)
1405 return length;
1406 server->total_read += length;
1407 remaining -= length;
1408 }
1409
1410 dequeue_mid(mid, rdata->result);
1411 return 0;
1412}
1413
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001414static inline size_t
1415read_rsp_size(void)
1416{
1417 return sizeof(READ_RSP);
1418}
1419
1420static inline unsigned int
1421read_data_offset(char *buf)
1422{
1423 READ_RSP *rsp = (READ_RSP *)buf;
1424 return le16_to_cpu(rsp->DataOffset);
1425}
1426
1427static inline unsigned int
1428read_data_length(char *buf)
1429{
1430 READ_RSP *rsp = (READ_RSP *)buf;
1431 return (le16_to_cpu(rsp->DataLengthHigh) << 16) +
1432 le16_to_cpu(rsp->DataLength);
1433}
1434
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001435static int
1436cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1437{
1438 int length, len;
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001439 unsigned int data_offset, data_len;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001440 struct cifs_readdata *rdata = mid->callback_data;
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001441 char *buf = server->smallbuf;
1442 unsigned int buflen = get_rfc1002_length(buf) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001443
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001444 cFYI(1, "%s: mid=%llu offset=%llu bytes=%u", __func__,
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001445 mid->mid, rdata->offset, rdata->bytes);
1446
1447 /*
1448 * read the rest of READ_RSP header (sans Data array), or whatever we
1449 * can if there's not enough data. At this point, we've read down to
1450 * the Mid.
1451 */
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001452 len = min_t(unsigned int, buflen, read_rsp_size()) -
1453 HEADER_SIZE(server) + 1;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001454
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001455 rdata->iov[0].iov_base = buf + HEADER_SIZE(server) - 1;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001456 rdata->iov[0].iov_len = len;
1457
1458 length = cifs_readv_from_socket(server, rdata->iov, 1, len);
1459 if (length < 0)
1460 return length;
1461 server->total_read += length;
1462
1463 /* Was the SMB read successful? */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001464 rdata->result = map_smb_to_linux_error(buf, false);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001465 if (rdata->result != 0) {
1466 cFYI(1, "%s: server returned error %d", __func__,
1467 rdata->result);
1468 return cifs_readv_discard(server, mid);
1469 }
1470
1471 /* Is there enough to get to the rest of the READ_RSP header? */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001472 if (server->total_read < read_rsp_size()) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001473 cFYI(1, "%s: server returned short header. got=%u expected=%zu",
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001474 __func__, server->total_read, read_rsp_size());
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001475 rdata->result = -EIO;
1476 return cifs_readv_discard(server, mid);
1477 }
1478
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001479 data_offset = read_data_offset(buf) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001480 if (data_offset < server->total_read) {
1481 /*
1482 * win2k8 sometimes sends an offset of 0 when the read
1483 * is beyond the EOF. Treat it as if the data starts just after
1484 * the header.
1485 */
1486 cFYI(1, "%s: data offset (%u) inside read response header",
1487 __func__, data_offset);
1488 data_offset = server->total_read;
1489 } else if (data_offset > MAX_CIFS_SMALL_BUFFER_SIZE) {
1490 /* data_offset is beyond the end of smallbuf */
1491 cFYI(1, "%s: data offset (%u) beyond end of smallbuf",
1492 __func__, data_offset);
1493 rdata->result = -EIO;
1494 return cifs_readv_discard(server, mid);
1495 }
1496
1497 cFYI(1, "%s: total_read=%u data_offset=%u", __func__,
1498 server->total_read, data_offset);
1499
1500 len = data_offset - server->total_read;
1501 if (len > 0) {
1502 /* read any junk before data into the rest of smallbuf */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001503 rdata->iov[0].iov_base = buf + server->total_read;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001504 rdata->iov[0].iov_len = len;
1505 length = cifs_readv_from_socket(server, rdata->iov, 1, len);
1506 if (length < 0)
1507 return length;
1508 server->total_read += length;
1509 }
1510
1511 /* set up first iov for signature check */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001512 rdata->iov[0].iov_base = buf;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001513 rdata->iov[0].iov_len = server->total_read;
1514 cFYI(1, "0: iov_base=%p iov_len=%zu",
1515 rdata->iov[0].iov_base, rdata->iov[0].iov_len);
1516
1517 /* how much data is in the response? */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001518 data_len = read_data_length(buf);
1519 if (data_offset + data_len > buflen) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001520 /* data_len is corrupt -- discard frame */
1521 rdata->result = -EIO;
1522 return cifs_readv_discard(server, mid);
1523 }
1524
1525 /* marshal up the page array */
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001526 len = rdata->marshal_iov(rdata, data_len);
1527 data_len -= len;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001528
1529 /* issue the read if we have any iovecs left to fill */
1530 if (rdata->nr_iov > 1) {
1531 length = cifs_readv_from_socket(server, &rdata->iov[1],
1532 rdata->nr_iov - 1, len);
1533 if (length < 0)
1534 return length;
1535 server->total_read += length;
1536 } else {
1537 length = 0;
1538 }
1539
1540 rdata->bytes = length;
1541
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001542 cFYI(1, "total_read=%u buflen=%u remaining=%u", server->total_read,
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001543 buflen, data_len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001544
1545 /* discard anything left over */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001546 if (server->total_read < buflen)
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001547 return cifs_readv_discard(server, mid);
1548
1549 dequeue_mid(mid, false);
1550 return length;
1551}
1552
1553static void
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001554cifs_readv_callback(struct mid_q_entry *mid)
1555{
1556 struct cifs_readdata *rdata = mid->callback_data;
1557 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1558 struct TCP_Server_Info *server = tcon->ses->server;
1559
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001560 cFYI(1, "%s: mid=%llu state=%d result=%d bytes=%u", __func__,
1561 mid->mid, mid->mid_state, rdata->result, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001562
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001563 switch (mid->mid_state) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001564 case MID_RESPONSE_RECEIVED:
1565 /* result already set, check signature */
1566 if (server->sec_mode &
1567 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
1568 if (cifs_verify_signature(rdata->iov, rdata->nr_iov,
1569 server, mid->sequence_number + 1))
1570 cERROR(1, "Unexpected SMB signature");
1571 }
1572 /* FIXME: should this be counted toward the initiating task? */
1573 task_io_account_read(rdata->bytes);
1574 cifs_stats_bytes_read(tcon, rdata->bytes);
1575 break;
1576 case MID_REQUEST_SUBMITTED:
1577 case MID_RETRY_NEEDED:
1578 rdata->result = -EAGAIN;
1579 break;
1580 default:
1581 rdata->result = -EIO;
1582 }
1583
Jeff Laytonda472fc2012-03-23 14:40:53 -04001584 queue_work(cifsiod_wq, &rdata->work);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001585 DeleteMidQEntry(mid);
Pavel Shilovsky2d86dbc2012-02-06 15:59:18 +04001586 cifs_add_credits(server, 1);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001587}
1588
1589/* cifs_async_readv - send an async write, and set up mid to handle result */
1590int
1591cifs_async_readv(struct cifs_readdata *rdata)
1592{
1593 int rc;
1594 READ_REQ *smb = NULL;
1595 int wct;
1596 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1597
1598 cFYI(1, "%s: offset=%llu bytes=%u", __func__,
1599 rdata->offset, rdata->bytes);
1600
1601 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1602 wct = 12;
1603 else {
1604 wct = 10; /* old style read */
1605 if ((rdata->offset >> 32) > 0) {
1606 /* can not handle this big offset for old */
1607 return -EIO;
1608 }
1609 }
1610
1611 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **)&smb);
1612 if (rc)
1613 return rc;
1614
1615 smb->hdr.Pid = cpu_to_le16((__u16)rdata->pid);
1616 smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16));
1617
1618 smb->AndXCommand = 0xFF; /* none */
1619 smb->Fid = rdata->cfile->netfid;
1620 smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF);
1621 if (wct == 12)
1622 smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32);
1623 smb->Remaining = 0;
1624 smb->MaxCount = cpu_to_le16(rdata->bytes & 0xFFFF);
1625 smb->MaxCountHigh = cpu_to_le32(rdata->bytes >> 16);
1626 if (wct == 12)
1627 smb->ByteCount = 0;
1628 else {
1629 /* old style read */
1630 struct smb_com_readx_req *smbr =
1631 (struct smb_com_readx_req *)smb;
1632 smbr->ByteCount = 0;
1633 }
1634
1635 /* 4 for RFC1001 length + 1 for BCC */
1636 rdata->iov[0].iov_base = smb;
1637 rdata->iov[0].iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
1638
Jeff Layton6993f742012-05-16 07:13:17 -04001639 kref_get(&rdata->refcount);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001640 rc = cifs_call_async(tcon->ses->server, rdata->iov, 1,
1641 cifs_readv_receive, cifs_readv_callback,
1642 rdata, false);
1643
1644 if (rc == 0)
1645 cifs_stats_inc(&tcon->num_reads);
Jeff Layton6993f742012-05-16 07:13:17 -04001646 else
1647 kref_put(&rdata->refcount, cifs_readdata_release);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001648
1649 cifs_small_buf_release(smb);
1650 return rc;
1651}
1652
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653int
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001654CIFSSMBRead(const int xid, struct cifs_io_parms *io_parms, unsigned int *nbytes,
Steve French50c2f752007-07-13 00:33:32 +00001655 char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656{
1657 int rc = -EACCES;
1658 READ_REQ *pSMB = NULL;
1659 READ_RSP *pSMBr = NULL;
1660 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001661 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001662 int resp_buf_type = 0;
1663 struct kvec iov[1];
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001664 __u32 pid = io_parms->pid;
1665 __u16 netfid = io_parms->netfid;
1666 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001667 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001668 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669
Joe Perchesb6b38f72010-04-21 03:50:45 +00001670 cFYI(1, "Reading %d bytes on fid %d", count, netfid);
Steve French790fe572007-07-07 19:25:05 +00001671 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001672 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001673 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001674 wct = 10; /* old style read */
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001675 if ((offset >> 32) > 0) {
Steve French4c3130e2008-12-09 00:28:16 +00001676 /* can not handle this big offset for old */
1677 return -EIO;
1678 }
1679 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680
1681 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001682 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683 if (rc)
1684 return rc;
1685
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001686 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1687 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1688
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689 /* tcon and ses pointer are checked in smb_init */
1690 if (tcon->ses->server == NULL)
1691 return -ECONNABORTED;
1692
Steve Frenchec637e32005-12-12 20:53:18 -08001693 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694 pSMB->Fid = netfid;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001695 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001696 if (wct == 12)
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001697 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001698
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699 pSMB->Remaining = 0;
1700 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1701 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001702 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001703 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1704 else {
1705 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001706 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001707 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001708 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001709 }
Steve Frenchec637e32005-12-12 20:53:18 -08001710
1711 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001712 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve Frencha761ac52007-10-18 21:45:27 +00001713 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Jeff Layton77499812011-01-11 07:24:23 -05001714 &resp_buf_type, CIFS_LOG_ERROR);
Steve Frencha4544342005-08-24 13:59:35 -07001715 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001716 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001718 cERROR(1, "Send error in read = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719 } else {
1720 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1721 data_length = data_length << 16;
1722 data_length += le16_to_cpu(pSMBr->DataLength);
1723 *nbytes = data_length;
1724
1725 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001726 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727 || (data_length > count)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001728 cFYI(1, "bad length %d for count %d",
1729 data_length, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730 rc = -EIO;
1731 *nbytes = 0;
1732 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001733 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001734 le16_to_cpu(pSMBr->DataOffset);
1735/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001736 cERROR(1, "Faulting on read rc = %d",rc);
Steve French50c2f752007-07-13 00:33:32 +00001737 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001738 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001739 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001740 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741 }
1742 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743
Steve French4b8f9302006-02-26 16:41:18 +00001744/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001745 if (*buf) {
1746 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001747 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001748 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001749 cifs_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001750 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001751 /* return buffer to caller to free */
1752 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001753 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001754 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001755 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001756 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001757 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001758
1759 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001760 since file handle passed in no longer valid */
1761 return rc;
1762}
1763
Steve Frenchec637e32005-12-12 20:53:18 -08001764
Linus Torvalds1da177e2005-04-16 15:20:36 -07001765int
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001766CIFSSMBWrite(const int xid, struct cifs_io_parms *io_parms,
1767 unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001768 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769{
1770 int rc = -EACCES;
1771 WRITE_REQ *pSMB = NULL;
1772 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001773 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774 __u32 bytes_sent;
1775 __u16 byte_count;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001776 __u32 pid = io_parms->pid;
1777 __u16 netfid = io_parms->netfid;
1778 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001779 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001780 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781
Steve Frencha24e2d72010-04-03 17:20:21 +00001782 *nbytes = 0;
1783
Joe Perchesb6b38f72010-04-21 03:50:45 +00001784 /* cFYI(1, "write at %lld %d bytes", offset, count);*/
Steve French790fe572007-07-07 19:25:05 +00001785 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001786 return -ECONNABORTED;
1787
Steve French790fe572007-07-07 19:25:05 +00001788 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001789 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001790 else {
Steve French1c955182005-08-30 20:58:07 -07001791 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001792 if ((offset >> 32) > 0) {
1793 /* can not handle big offset for old srv */
1794 return -EIO;
1795 }
1796 }
Steve French1c955182005-08-30 20:58:07 -07001797
1798 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799 (void **) &pSMBr);
1800 if (rc)
1801 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001802
1803 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1804 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1805
Linus Torvalds1da177e2005-04-16 15:20:36 -07001806 /* tcon and ses pointer are checked in smb_init */
1807 if (tcon->ses->server == NULL)
1808 return -ECONNABORTED;
1809
1810 pSMB->AndXCommand = 0xFF; /* none */
1811 pSMB->Fid = netfid;
1812 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001813 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001814 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001815
Linus Torvalds1da177e2005-04-16 15:20:36 -07001816 pSMB->Reserved = 0xFFFFFFFF;
1817 pSMB->WriteMode = 0;
1818 pSMB->Remaining = 0;
1819
Steve French50c2f752007-07-13 00:33:32 +00001820 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821 can send more if LARGE_WRITE_X capability returned by the server and if
1822 our buffer is big enough or if we convert to iovecs on socket writes
1823 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001824 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001825 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1826 } else {
1827 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1828 & ~0xFF;
1829 }
1830
1831 if (bytes_sent > count)
1832 bytes_sent = count;
1833 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001834 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001835 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001836 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001837 else if (ubuf) {
1838 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001839 cifs_buf_release(pSMB);
1840 return -EFAULT;
1841 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001842 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843 /* No buffer */
1844 cifs_buf_release(pSMB);
1845 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001846 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001847 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001848 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001849 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001850 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001851
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1853 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001854 inc_rfc1001_len(pSMB, byte_count);
Steve French1c955182005-08-30 20:58:07 -07001855
Steve French790fe572007-07-07 19:25:05 +00001856 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001857 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001858 else { /* old style write has byte count 4 bytes earlier
1859 so 4 bytes pad */
1860 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001861 (struct smb_com_writex_req *)pSMB;
1862 pSMBW->ByteCount = cpu_to_le16(byte_count);
1863 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864
1865 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1866 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001867 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00001869 cFYI(1, "Send error in write = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870 } else {
1871 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1872 *nbytes = (*nbytes) << 16;
1873 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301874
1875 /*
1876 * Mask off high 16 bits when bytes written as returned by the
1877 * server is greater than bytes requested by the client. Some
1878 * OS/2 servers are known to set incorrect CountHigh values.
1879 */
1880 if (*nbytes > count)
1881 *nbytes &= 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001882 }
1883
1884 cifs_buf_release(pSMB);
1885
Steve French50c2f752007-07-13 00:33:32 +00001886 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887 since file handle passed in no longer valid */
1888
1889 return rc;
1890}
1891
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001892void
1893cifs_writedata_release(struct kref *refcount)
1894{
1895 struct cifs_writedata *wdata = container_of(refcount,
1896 struct cifs_writedata, refcount);
1897
1898 if (wdata->cfile)
1899 cifsFileInfo_put(wdata->cfile);
1900
1901 kfree(wdata);
1902}
1903
1904/*
1905 * Write failed with a retryable error. Resend the write request. It's also
1906 * possible that the page was redirtied so re-clean the page.
1907 */
1908static void
1909cifs_writev_requeue(struct cifs_writedata *wdata)
1910{
1911 int i, rc;
1912 struct inode *inode = wdata->cfile->dentry->d_inode;
1913
1914 for (i = 0; i < wdata->nr_pages; i++) {
1915 lock_page(wdata->pages[i]);
1916 clear_page_dirty_for_io(wdata->pages[i]);
1917 }
1918
1919 do {
1920 rc = cifs_async_writev(wdata);
1921 } while (rc == -EAGAIN);
1922
1923 for (i = 0; i < wdata->nr_pages; i++) {
1924 if (rc != 0)
1925 SetPageError(wdata->pages[i]);
1926 unlock_page(wdata->pages[i]);
1927 }
1928
1929 mapping_set_error(inode->i_mapping, rc);
1930 kref_put(&wdata->refcount, cifs_writedata_release);
1931}
1932
Jeff Laytonc2e87642012-03-23 14:40:55 -04001933void
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001934cifs_writev_complete(struct work_struct *work)
1935{
1936 struct cifs_writedata *wdata = container_of(work,
1937 struct cifs_writedata, work);
1938 struct inode *inode = wdata->cfile->dentry->d_inode;
1939 int i = 0;
1940
1941 if (wdata->result == 0) {
Jeff Layton597b0272012-03-23 14:40:56 -04001942 spin_lock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001943 cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
Jeff Layton597b0272012-03-23 14:40:56 -04001944 spin_unlock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001945 cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
1946 wdata->bytes);
1947 } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
1948 return cifs_writev_requeue(wdata);
1949
1950 for (i = 0; i < wdata->nr_pages; i++) {
1951 struct page *page = wdata->pages[i];
1952 if (wdata->result == -EAGAIN)
1953 __set_page_dirty_nobuffers(page);
1954 else if (wdata->result < 0)
1955 SetPageError(page);
1956 end_page_writeback(page);
1957 page_cache_release(page);
1958 }
1959 if (wdata->result != -EAGAIN)
1960 mapping_set_error(inode->i_mapping, wdata->result);
1961 kref_put(&wdata->refcount, cifs_writedata_release);
1962}
1963
1964struct cifs_writedata *
Jeff Laytonc2e87642012-03-23 14:40:55 -04001965cifs_writedata_alloc(unsigned int nr_pages, work_func_t complete)
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001966{
1967 struct cifs_writedata *wdata;
1968
1969 /* this would overflow */
1970 if (nr_pages == 0) {
1971 cERROR(1, "%s: called with nr_pages == 0!", __func__);
1972 return NULL;
1973 }
1974
1975 /* writedata + number of page pointers */
1976 wdata = kzalloc(sizeof(*wdata) +
1977 sizeof(struct page *) * (nr_pages - 1), GFP_NOFS);
1978 if (wdata != NULL) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001979 kref_init(&wdata->refcount);
Jeff Laytonda82f7e2012-03-23 14:40:56 -04001980 INIT_LIST_HEAD(&wdata->list);
1981 init_completion(&wdata->done);
1982 INIT_WORK(&wdata->work, complete);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001983 }
1984 return wdata;
1985}
1986
1987/*
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001988 * Check the mid_state and signature on received buffer (if any), and queue the
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001989 * workqueue completion task.
1990 */
1991static void
1992cifs_writev_callback(struct mid_q_entry *mid)
1993{
1994 struct cifs_writedata *wdata = mid->callback_data;
Steve French96daf2b2011-05-27 04:34:02 +00001995 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001996 unsigned int written;
1997 WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
1998
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001999 switch (mid->mid_state) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002000 case MID_RESPONSE_RECEIVED:
2001 wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
2002 if (wdata->result != 0)
2003 break;
2004
2005 written = le16_to_cpu(smb->CountHigh);
2006 written <<= 16;
2007 written += le16_to_cpu(smb->Count);
2008 /*
2009 * Mask off high 16 bits when bytes written as returned
2010 * by the server is greater than bytes requested by the
2011 * client. OS/2 servers are known to set incorrect
2012 * CountHigh values.
2013 */
2014 if (written > wdata->bytes)
2015 written &= 0xFFFF;
2016
2017 if (written < wdata->bytes)
2018 wdata->result = -ENOSPC;
2019 else
2020 wdata->bytes = written;
2021 break;
2022 case MID_REQUEST_SUBMITTED:
2023 case MID_RETRY_NEEDED:
2024 wdata->result = -EAGAIN;
2025 break;
2026 default:
2027 wdata->result = -EIO;
2028 break;
2029 }
2030
Jeff Laytonda472fc2012-03-23 14:40:53 -04002031 queue_work(cifsiod_wq, &wdata->work);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002032 DeleteMidQEntry(mid);
Pavel Shilovsky2d86dbc2012-02-06 15:59:18 +04002033 cifs_add_credits(tcon->ses->server, 1);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002034}
2035
2036/* cifs_async_writev - send an async write, and set up mid to handle result */
2037int
2038cifs_async_writev(struct cifs_writedata *wdata)
2039{
2040 int i, rc = -EACCES;
2041 WRITE_REQ *smb = NULL;
2042 int wct;
Steve French96daf2b2011-05-27 04:34:02 +00002043 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002044 struct kvec *iov = NULL;
2045
2046 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
2047 wct = 14;
2048 } else {
2049 wct = 12;
2050 if (wdata->offset >> 32 > 0) {
2051 /* can not handle big offset for old srv */
2052 return -EIO;
2053 }
2054 }
2055
2056 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
2057 if (rc)
2058 goto async_writev_out;
2059
2060 /* 1 iov per page + 1 for header */
2061 iov = kzalloc((wdata->nr_pages + 1) * sizeof(*iov), GFP_NOFS);
2062 if (iov == NULL) {
2063 rc = -ENOMEM;
2064 goto async_writev_out;
2065 }
2066
Jeff Laytonfe5f5d22012-03-23 14:40:55 -04002067 smb->hdr.Pid = cpu_to_le16((__u16)wdata->pid);
2068 smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16));
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002069
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002070 smb->AndXCommand = 0xFF; /* none */
2071 smb->Fid = wdata->cfile->netfid;
2072 smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
2073 if (wct == 14)
2074 smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
2075 smb->Reserved = 0xFFFFFFFF;
2076 smb->WriteMode = 0;
2077 smb->Remaining = 0;
2078
2079 smb->DataOffset =
2080 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
2081
2082 /* 4 for RFC1001 length + 1 for BCC */
2083 iov[0].iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4 + 1;
2084 iov[0].iov_base = smb;
2085
Jeff Laytone9492872012-03-23 14:40:56 -04002086 /*
2087 * This function should marshal up the page array into the kvec
2088 * array, reserving [0] for the header. It should kmap the pages
2089 * and set the iov_len properly for each one. It may also set
2090 * wdata->bytes too.
2091 */
2092 wdata->marshal_iov(iov, wdata);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002093
2094 cFYI(1, "async write at %llu %u bytes", wdata->offset, wdata->bytes);
2095
2096 smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
2097 smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16);
2098
2099 if (wct == 14) {
2100 inc_rfc1001_len(&smb->hdr, wdata->bytes + 1);
2101 put_bcc(wdata->bytes + 1, &smb->hdr);
2102 } else {
2103 /* wct == 12 */
2104 struct smb_com_writex_req *smbw =
2105 (struct smb_com_writex_req *)smb;
2106 inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
2107 put_bcc(wdata->bytes + 5, &smbw->hdr);
2108 iov[0].iov_len += 4; /* pad bigger by four bytes */
2109 }
2110
2111 kref_get(&wdata->refcount);
2112 rc = cifs_call_async(tcon->ses->server, iov, wdata->nr_pages + 1,
Jeff Layton44d22d82011-10-19 15:29:49 -04002113 NULL, cifs_writev_callback, wdata, false);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002114
2115 if (rc == 0)
2116 cifs_stats_inc(&tcon->num_writes);
2117 else
2118 kref_put(&wdata->refcount, cifs_writedata_release);
2119
2120 /* send is done, unmap pages */
2121 for (i = 0; i < wdata->nr_pages; i++)
2122 kunmap(wdata->pages[i]);
2123
2124async_writev_out:
2125 cifs_small_buf_release(smb);
2126 kfree(iov);
2127 return rc;
2128}
2129
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002130int
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002131CIFSSMBWrite2(const int xid, struct cifs_io_parms *io_parms,
2132 unsigned int *nbytes, struct kvec *iov, int n_vec,
2133 const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002134{
2135 int rc = -EACCES;
2136 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08002137 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002138 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08002139 int resp_buf_type = 0;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002140 __u32 pid = io_parms->pid;
2141 __u16 netfid = io_parms->netfid;
2142 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00002143 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002144 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002145
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04002146 *nbytes = 0;
2147
Joe Perchesb6b38f72010-04-21 03:50:45 +00002148 cFYI(1, "write2 at %lld %d bytes", (long long)offset, count);
Steve Frenchff7feac2005-11-15 16:45:16 -08002149
Steve French4c3130e2008-12-09 00:28:16 +00002150 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07002151 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00002152 } else {
Steve French8cc64c62005-10-03 13:49:43 -07002153 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00002154 if ((offset >> 32) > 0) {
2155 /* can not handle big offset for old srv */
2156 return -EIO;
2157 }
2158 }
Steve French8cc64c62005-10-03 13:49:43 -07002159 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002160 if (rc)
2161 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002162
2163 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
2164 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
2165
Linus Torvalds1da177e2005-04-16 15:20:36 -07002166 /* tcon and ses pointer are checked in smb_init */
2167 if (tcon->ses->server == NULL)
2168 return -ECONNABORTED;
2169
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002170 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002171 pSMB->Fid = netfid;
2172 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00002173 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002174 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175 pSMB->Reserved = 0xFFFFFFFF;
2176 pSMB->WriteMode = 0;
2177 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002178
Linus Torvalds1da177e2005-04-16 15:20:36 -07002179 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00002180 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002181
Steve French3e844692005-10-03 13:37:24 -07002182 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
2183 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002184 /* header + 1 byte pad */
2185 smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
Steve French790fe572007-07-07 19:25:05 +00002186 if (wct == 14)
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002187 inc_rfc1001_len(pSMB, count + 1);
Steve French8cc64c62005-10-03 13:49:43 -07002188 else /* wct == 12 */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002189 inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
Steve French790fe572007-07-07 19:25:05 +00002190 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002191 pSMB->ByteCount = cpu_to_le16(count + 1);
2192 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00002193 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07002194 (struct smb_com_writex_req *)pSMB;
2195 pSMBW->ByteCount = cpu_to_le16(count + 5);
2196 }
Steve French3e844692005-10-03 13:37:24 -07002197 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00002198 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08002199 iov[0].iov_len = smb_hdr_len + 4;
2200 else /* wct == 12 pad bigger by four bytes */
2201 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00002202
Steve French3e844692005-10-03 13:37:24 -07002203
Steve Frenchec637e32005-12-12 20:53:18 -08002204 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French133672e2007-11-13 22:41:37 +00002205 long_op);
Steve Frencha4544342005-08-24 13:59:35 -07002206 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002207 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002208 cFYI(1, "Send error Write2 = %d", rc);
Steve French790fe572007-07-07 19:25:05 +00002209 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08002210 /* presumably this can not happen, but best to be safe */
2211 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002212 } else {
Steve Frenchad7a2922008-02-07 23:25:02 +00002213 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002214 *nbytes = le16_to_cpu(pSMBr->CountHigh);
2215 *nbytes = (*nbytes) << 16;
2216 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05302217
2218 /*
2219 * Mask off high 16 bits when bytes written as returned by the
2220 * server is greater than bytes requested by the client. OS/2
2221 * servers are known to set incorrect CountHigh values.
2222 */
2223 if (*nbytes > count)
2224 *nbytes &= 0xFFFF;
Steve French50c2f752007-07-13 00:33:32 +00002225 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002226
Steve French4b8f9302006-02-26 16:41:18 +00002227/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00002228 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002229 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00002230 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002231 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232
Steve French50c2f752007-07-13 00:33:32 +00002233 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002234 since file handle passed in no longer valid */
2235
2236 return rc;
2237}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002238
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002239int cifs_lockv(const int xid, struct cifs_tcon *tcon, const __u16 netfid,
2240 const __u8 lock_type, const __u32 num_unlock,
2241 const __u32 num_lock, LOCKING_ANDX_RANGE *buf)
2242{
2243 int rc = 0;
2244 LOCK_REQ *pSMB = NULL;
2245 struct kvec iov[2];
2246 int resp_buf_type;
2247 __u16 count;
2248
2249 cFYI(1, "cifs_lockv num lock %d num unlock %d", num_lock, num_unlock);
2250
2251 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2252 if (rc)
2253 return rc;
2254
2255 pSMB->Timeout = 0;
2256 pSMB->NumberOfLocks = cpu_to_le16(num_lock);
2257 pSMB->NumberOfUnlocks = cpu_to_le16(num_unlock);
2258 pSMB->LockType = lock_type;
2259 pSMB->AndXCommand = 0xFF; /* none */
2260 pSMB->Fid = netfid; /* netfid stays le */
2261
2262 count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2263 inc_rfc1001_len(pSMB, count);
2264 pSMB->ByteCount = cpu_to_le16(count);
2265
2266 iov[0].iov_base = (char *)pSMB;
2267 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 -
2268 (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2269 iov[1].iov_base = (char *)buf;
2270 iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2271
2272 cifs_stats_inc(&tcon->num_locks);
2273 rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP);
2274 if (rc)
2275 cFYI(1, "Send error in cifs_lockv = %d", rc);
2276
2277 return rc;
2278}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002279
Linus Torvalds1da177e2005-04-16 15:20:36 -07002280int
Steve French96daf2b2011-05-27 04:34:02 +00002281CIFSSMBLock(const int xid, struct cifs_tcon *tcon,
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002282 const __u16 smb_file_id, const __u32 netpid, const __u64 len,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002283 const __u64 offset, const __u32 numUnlock,
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002284 const __u32 numLock, const __u8 lockType,
2285 const bool waitFlag, const __u8 oplock_level)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002286{
2287 int rc = 0;
2288 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002289/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002290 int bytes_returned;
2291 int timeout = 0;
2292 __u16 count;
2293
Joe Perchesb6b38f72010-04-21 03:50:45 +00002294 cFYI(1, "CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock);
Steve French46810cb2005-04-28 22:41:09 -07002295 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2296
Linus Torvalds1da177e2005-04-16 15:20:36 -07002297 if (rc)
2298 return rc;
2299
Steve French790fe572007-07-07 19:25:05 +00002300 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Steve French133672e2007-11-13 22:41:37 +00002301 timeout = CIFS_ASYNC_OP; /* no response expected */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002302 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00002303 } else if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00002304 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002305 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
2306 } else {
2307 pSMB->Timeout = 0;
2308 }
2309
2310 pSMB->NumberOfLocks = cpu_to_le16(numLock);
2311 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
2312 pSMB->LockType = lockType;
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002313 pSMB->OplockLevel = oplock_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002314 pSMB->AndXCommand = 0xFF; /* none */
2315 pSMB->Fid = smb_file_id; /* netfid stays le */
2316
Steve French790fe572007-07-07 19:25:05 +00002317 if ((numLock != 0) || (numUnlock != 0)) {
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002318 pSMB->Locks[0].Pid = cpu_to_le16(netpid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002319 /* BB where to store pid high? */
2320 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
2321 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
2322 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
2323 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
2324 count = sizeof(LOCKING_ANDX_RANGE);
2325 } else {
2326 /* oplock break */
2327 count = 0;
2328 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002329 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002330 pSMB->ByteCount = cpu_to_le16(count);
2331
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002332 if (waitFlag) {
2333 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002334 (struct smb_hdr *) pSMB, &bytes_returned);
Steve French133672e2007-11-13 22:41:37 +00002335 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002336 } else {
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002337 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, timeout);
Steve French133672e2007-11-13 22:41:37 +00002338 /* SMB buffer freed by function above */
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002339 }
Steve Frencha4544342005-08-24 13:59:35 -07002340 cifs_stats_inc(&tcon->num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002341 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002342 cFYI(1, "Send error in Lock = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002343
Steve French50c2f752007-07-13 00:33:32 +00002344 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002345 since file handle passed in no longer valid */
2346 return rc;
2347}
2348
2349int
Steve French96daf2b2011-05-27 04:34:02 +00002350CIFSSMBPosixLock(const int xid, struct cifs_tcon *tcon,
Pavel Shilovsky4f6bcec2011-10-22 15:33:30 +04002351 const __u16 smb_file_id, const __u32 netpid, const int get_flag,
2352 const __u64 len, struct file_lock *pLockData,
2353 const __u16 lock_type, const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00002354{
2355 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2356 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00002357 struct cifs_posix_lock *parm_data;
2358 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00002359 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00002360 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00002361 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00002362 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00002363 struct kvec iov[1];
Steve French08547b02006-02-28 22:39:25 +00002364
Joe Perchesb6b38f72010-04-21 03:50:45 +00002365 cFYI(1, "Posix Lock");
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002366
Steve French790fe572007-07-07 19:25:05 +00002367 if (pLockData == NULL)
Marcin Slusarzed5f0372008-05-13 04:01:01 +00002368 return -EINVAL;
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002369
Steve French08547b02006-02-28 22:39:25 +00002370 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
2371
2372 if (rc)
2373 return rc;
2374
2375 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
2376
Steve French50c2f752007-07-13 00:33:32 +00002377 params = 6;
Steve French08547b02006-02-28 22:39:25 +00002378 pSMB->MaxSetupCount = 0;
2379 pSMB->Reserved = 0;
2380 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00002381 pSMB->Reserved2 = 0;
2382 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2383 offset = param_offset + params;
2384
Steve French08547b02006-02-28 22:39:25 +00002385 count = sizeof(struct cifs_posix_lock);
2386 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002387 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00002388 pSMB->SetupCount = 1;
2389 pSMB->Reserved3 = 0;
Steve French790fe572007-07-07 19:25:05 +00002390 if (get_flag)
Steve French08547b02006-02-28 22:39:25 +00002391 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2392 else
2393 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2394 byte_count = 3 /* pad */ + params + count;
2395 pSMB->DataCount = cpu_to_le16(count);
2396 pSMB->ParameterCount = cpu_to_le16(params);
2397 pSMB->TotalDataCount = pSMB->DataCount;
2398 pSMB->TotalParameterCount = pSMB->ParameterCount;
2399 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00002400 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00002401 (((char *) &pSMB->hdr.Protocol) + offset);
2402
2403 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00002404 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00002405 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00002406 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00002407 pSMB->Timeout = cpu_to_le32(-1);
2408 } else
2409 pSMB->Timeout = 0;
2410
Pavel Shilovsky4f6bcec2011-10-22 15:33:30 +04002411 parm_data->pid = cpu_to_le32(netpid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002412 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00002413 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00002414
2415 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00002416 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00002417 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
2418 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002419 inc_rfc1001_len(pSMB, byte_count);
Steve French08547b02006-02-28 22:39:25 +00002420 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002421 if (waitFlag) {
2422 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2423 (struct smb_hdr *) pSMBr, &bytes_returned);
2424 } else {
Steve French133672e2007-11-13 22:41:37 +00002425 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002426 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French133672e2007-11-13 22:41:37 +00002427 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
2428 &resp_buf_type, timeout);
2429 pSMB = NULL; /* request buf already freed by SendReceive2. Do
2430 not try to free it twice below on exit */
2431 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002432 }
2433
Steve French08547b02006-02-28 22:39:25 +00002434 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002435 cFYI(1, "Send error in Posix Lock = %d", rc);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002436 } else if (get_flag) {
2437 /* lock structure can be returned on get */
2438 __u16 data_offset;
2439 __u16 data_count;
2440 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00002441
Jeff Layton820a8032011-05-04 08:05:26 -04002442 if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002443 rc = -EIO; /* bad smb */
2444 goto plk_err_exit;
2445 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002446 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2447 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00002448 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002449 rc = -EIO;
2450 goto plk_err_exit;
2451 }
2452 parm_data = (struct cifs_posix_lock *)
2453 ((char *)&pSMBr->hdr.Protocol + data_offset);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002454 if (parm_data->lock_type == __constant_cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002455 pLockData->fl_type = F_UNLCK;
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002456 else {
2457 if (parm_data->lock_type ==
2458 __constant_cpu_to_le16(CIFS_RDLCK))
2459 pLockData->fl_type = F_RDLCK;
2460 else if (parm_data->lock_type ==
2461 __constant_cpu_to_le16(CIFS_WRLCK))
2462 pLockData->fl_type = F_WRLCK;
2463
Steve French5443d132011-03-13 05:08:25 +00002464 pLockData->fl_start = le64_to_cpu(parm_data->start);
2465 pLockData->fl_end = pLockData->fl_start +
2466 le64_to_cpu(parm_data->length) - 1;
2467 pLockData->fl_pid = le32_to_cpu(parm_data->pid);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002468 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002469 }
Steve French50c2f752007-07-13 00:33:32 +00002470
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002471plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00002472 if (pSMB)
2473 cifs_small_buf_release(pSMB);
2474
Steve French133672e2007-11-13 22:41:37 +00002475 if (resp_buf_type == CIFS_SMALL_BUFFER)
2476 cifs_small_buf_release(iov[0].iov_base);
2477 else if (resp_buf_type == CIFS_LARGE_BUFFER)
2478 cifs_buf_release(iov[0].iov_base);
2479
Steve French08547b02006-02-28 22:39:25 +00002480 /* Note: On -EAGAIN error only caller can retry on handle based calls
2481 since file handle passed in no longer valid */
2482
2483 return rc;
2484}
2485
2486
2487int
Steve French96daf2b2011-05-27 04:34:02 +00002488CIFSSMBClose(const int xid, struct cifs_tcon *tcon, int smb_file_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002489{
2490 int rc = 0;
2491 CLOSE_REQ *pSMB = NULL;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002492 cFYI(1, "In CIFSSMBClose");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002493
2494/* do not retry on dead session on close */
2495 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00002496 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002497 return 0;
2498 if (rc)
2499 return rc;
2500
Linus Torvalds1da177e2005-04-16 15:20:36 -07002501 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e2006-10-02 05:53:29 +00002502 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002503 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002504 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002505 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002506 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00002507 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002508 /* EINTR is expected when user ctl-c to kill app */
Joe Perchesb6b38f72010-04-21 03:50:45 +00002509 cERROR(1, "Send error in Close = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002510 }
2511 }
2512
Linus Torvalds1da177e2005-04-16 15:20:36 -07002513 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00002514 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515 rc = 0;
2516
2517 return rc;
2518}
2519
2520int
Steve French96daf2b2011-05-27 04:34:02 +00002521CIFSSMBFlush(const int xid, struct cifs_tcon *tcon, int smb_file_id)
Steve Frenchb298f222009-02-21 21:17:43 +00002522{
2523 int rc = 0;
2524 FLUSH_REQ *pSMB = NULL;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002525 cFYI(1, "In CIFSSMBFlush");
Steve Frenchb298f222009-02-21 21:17:43 +00002526
2527 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
2528 if (rc)
2529 return rc;
2530
2531 pSMB->FileID = (__u16) smb_file_id;
2532 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002533 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frenchb298f222009-02-21 21:17:43 +00002534 cifs_stats_inc(&tcon->num_flushes);
2535 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002536 cERROR(1, "Send error in Flush = %d", rc);
Steve Frenchb298f222009-02-21 21:17:43 +00002537
2538 return rc;
2539}
2540
2541int
Steve French96daf2b2011-05-27 04:34:02 +00002542CIFSSMBRename(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002543 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002544 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002545{
2546 int rc = 0;
2547 RENAME_REQ *pSMB = NULL;
2548 RENAME_RSP *pSMBr = NULL;
2549 int bytes_returned;
2550 int name_len, name_len2;
2551 __u16 count;
2552
Joe Perchesb6b38f72010-04-21 03:50:45 +00002553 cFYI(1, "In CIFSSMBRename");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002554renameRetry:
2555 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
2556 (void **) &pSMBr);
2557 if (rc)
2558 return rc;
2559
2560 pSMB->BufferFormat = 0x04;
2561 pSMB->SearchAttributes =
2562 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2563 ATTR_DIRECTORY);
2564
2565 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2566 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06002567 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, fromName,
2568 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002569 name_len++; /* trailing null */
2570 name_len *= 2;
2571 pSMB->OldFileName[name_len] = 0x04; /* pad */
2572 /* protocol requires ASCII signature byte on Unicode string */
2573 pSMB->OldFileName[name_len + 1] = 0x00;
2574 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002575 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2576 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002577 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2578 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002579 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580 name_len = strnlen(fromName, PATH_MAX);
2581 name_len++; /* trailing null */
2582 strncpy(pSMB->OldFileName, fromName, name_len);
2583 name_len2 = strnlen(toName, PATH_MAX);
2584 name_len2++; /* trailing null */
2585 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2586 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2587 name_len2++; /* trailing null */
2588 name_len2++; /* signature byte */
2589 }
2590
2591 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002592 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002593 pSMB->ByteCount = cpu_to_le16(count);
2594
2595 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2596 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002597 cifs_stats_inc(&tcon->num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002598 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002599 cFYI(1, "Send error in rename = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002600
Linus Torvalds1da177e2005-04-16 15:20:36 -07002601 cifs_buf_release(pSMB);
2602
2603 if (rc == -EAGAIN)
2604 goto renameRetry;
2605
2606 return rc;
2607}
2608
Steve French96daf2b2011-05-27 04:34:02 +00002609int CIFSSMBRenameOpenFile(const int xid, struct cifs_tcon *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002610 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002611 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002612{
2613 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2614 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002615 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002616 char *data_offset;
2617 char dummy_string[30];
2618 int rc = 0;
2619 int bytes_returned = 0;
2620 int len_of_str;
2621 __u16 params, param_offset, offset, count, byte_count;
2622
Joe Perchesb6b38f72010-04-21 03:50:45 +00002623 cFYI(1, "Rename to File by handle");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002624 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2625 (void **) &pSMBr);
2626 if (rc)
2627 return rc;
2628
2629 params = 6;
2630 pSMB->MaxSetupCount = 0;
2631 pSMB->Reserved = 0;
2632 pSMB->Flags = 0;
2633 pSMB->Timeout = 0;
2634 pSMB->Reserved2 = 0;
2635 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2636 offset = param_offset + params;
2637
2638 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2639 rename_info = (struct set_file_rename *) data_offset;
2640 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002641 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002642 pSMB->SetupCount = 1;
2643 pSMB->Reserved3 = 0;
2644 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2645 byte_count = 3 /* pad */ + params;
2646 pSMB->ParameterCount = cpu_to_le16(params);
2647 pSMB->TotalParameterCount = pSMB->ParameterCount;
2648 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2649 pSMB->DataOffset = cpu_to_le16(offset);
2650 /* construct random name ".cifs_tmp<inodenum><mid>" */
2651 rename_info->overwrite = cpu_to_le32(1);
2652 rename_info->root_fid = 0;
2653 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002654 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002655 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
Steve Frenchacbbb762012-01-18 22:32:33 -06002656 len_of_str =
2657 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002658 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002659 } else {
Steve Frenchacbbb762012-01-18 22:32:33 -06002660 len_of_str =
2661 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002662 target_name, PATH_MAX, nls_codepage,
2663 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002664 }
2665 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002666 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002667 byte_count += count;
2668 pSMB->DataCount = cpu_to_le16(count);
2669 pSMB->TotalDataCount = pSMB->DataCount;
2670 pSMB->Fid = netfid;
2671 pSMB->InformationLevel =
2672 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2673 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002674 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002675 pSMB->ByteCount = cpu_to_le16(byte_count);
2676 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002677 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002678 cifs_stats_inc(&pTcon->num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002679 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002680 cFYI(1, "Send error in Rename (by file handle) = %d", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07002681
Linus Torvalds1da177e2005-04-16 15:20:36 -07002682 cifs_buf_release(pSMB);
2683
2684 /* Note: On -EAGAIN error only caller can retry on handle based calls
2685 since file handle passed in no longer valid */
2686
2687 return rc;
2688}
2689
2690int
Steve French96daf2b2011-05-27 04:34:02 +00002691CIFSSMBCopy(const int xid, struct cifs_tcon *tcon, const char *fromName,
Steve French50c2f752007-07-13 00:33:32 +00002692 const __u16 target_tid, const char *toName, const int flags,
2693 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002694{
2695 int rc = 0;
2696 COPY_REQ *pSMB = NULL;
2697 COPY_RSP *pSMBr = NULL;
2698 int bytes_returned;
2699 int name_len, name_len2;
2700 __u16 count;
2701
Joe Perchesb6b38f72010-04-21 03:50:45 +00002702 cFYI(1, "In CIFSSMBCopy");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002703copyRetry:
2704 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2705 (void **) &pSMBr);
2706 if (rc)
2707 return rc;
2708
2709 pSMB->BufferFormat = 0x04;
2710 pSMB->Tid2 = target_tid;
2711
2712 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2713
2714 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002715 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2716 fromName, PATH_MAX, nls_codepage,
2717 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002718 name_len++; /* trailing null */
2719 name_len *= 2;
2720 pSMB->OldFileName[name_len] = 0x04; /* pad */
2721 /* protocol requires ASCII signature byte on Unicode string */
2722 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002723 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002724 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2725 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002726 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2727 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002728 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002729 name_len = strnlen(fromName, PATH_MAX);
2730 name_len++; /* trailing null */
2731 strncpy(pSMB->OldFileName, fromName, name_len);
2732 name_len2 = strnlen(toName, PATH_MAX);
2733 name_len2++; /* trailing null */
2734 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2735 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2736 name_len2++; /* trailing null */
2737 name_len2++; /* signature byte */
2738 }
2739
2740 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002741 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002742 pSMB->ByteCount = cpu_to_le16(count);
2743
2744 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2745 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2746 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002747 cFYI(1, "Send error in copy = %d with %d files copied",
2748 rc, le16_to_cpu(pSMBr->CopyCount));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002749 }
Steve French0d817bc2008-05-22 02:02:03 +00002750 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002751
2752 if (rc == -EAGAIN)
2753 goto copyRetry;
2754
2755 return rc;
2756}
2757
2758int
Steve French96daf2b2011-05-27 04:34:02 +00002759CIFSUnixCreateSymLink(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002760 const char *fromName, const char *toName,
2761 const struct nls_table *nls_codepage)
2762{
2763 TRANSACTION2_SPI_REQ *pSMB = NULL;
2764 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2765 char *data_offset;
2766 int name_len;
2767 int name_len_target;
2768 int rc = 0;
2769 int bytes_returned = 0;
2770 __u16 params, param_offset, offset, byte_count;
2771
Joe Perchesb6b38f72010-04-21 03:50:45 +00002772 cFYI(1, "In Symlink Unix style");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002773createSymLinkRetry:
2774 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2775 (void **) &pSMBr);
2776 if (rc)
2777 return rc;
2778
2779 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2780 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06002781 cifs_strtoUTF16((__le16 *) pSMB->FileName, fromName,
2782 /* find define for this maxpathcomponent */
2783 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002784 name_len++; /* trailing null */
2785 name_len *= 2;
2786
Steve French50c2f752007-07-13 00:33:32 +00002787 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002788 name_len = strnlen(fromName, PATH_MAX);
2789 name_len++; /* trailing null */
2790 strncpy(pSMB->FileName, fromName, name_len);
2791 }
2792 params = 6 + name_len;
2793 pSMB->MaxSetupCount = 0;
2794 pSMB->Reserved = 0;
2795 pSMB->Flags = 0;
2796 pSMB->Timeout = 0;
2797 pSMB->Reserved2 = 0;
2798 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002799 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002800 offset = param_offset + params;
2801
2802 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2803 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2804 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06002805 cifs_strtoUTF16((__le16 *) data_offset, toName, PATH_MAX
2806 /* find define for this maxpathcomponent */
2807 , nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002808 name_len_target++; /* trailing null */
2809 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002810 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002811 name_len_target = strnlen(toName, PATH_MAX);
2812 name_len_target++; /* trailing null */
2813 strncpy(data_offset, toName, name_len_target);
2814 }
2815
2816 pSMB->MaxParameterCount = cpu_to_le16(2);
2817 /* BB find exact max on data count below from sess */
2818 pSMB->MaxDataCount = cpu_to_le16(1000);
2819 pSMB->SetupCount = 1;
2820 pSMB->Reserved3 = 0;
2821 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2822 byte_count = 3 /* pad */ + params + name_len_target;
2823 pSMB->DataCount = cpu_to_le16(name_len_target);
2824 pSMB->ParameterCount = cpu_to_le16(params);
2825 pSMB->TotalDataCount = pSMB->DataCount;
2826 pSMB->TotalParameterCount = pSMB->ParameterCount;
2827 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2828 pSMB->DataOffset = cpu_to_le16(offset);
2829 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2830 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002831 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832 pSMB->ByteCount = cpu_to_le16(byte_count);
2833 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2834 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002835 cifs_stats_inc(&tcon->num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002836 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002837 cFYI(1, "Send error in SetPathInfo create symlink = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002838
Steve French0d817bc2008-05-22 02:02:03 +00002839 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002840
2841 if (rc == -EAGAIN)
2842 goto createSymLinkRetry;
2843
2844 return rc;
2845}
2846
2847int
Steve French96daf2b2011-05-27 04:34:02 +00002848CIFSUnixCreateHardLink(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002849 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002850 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002851{
2852 TRANSACTION2_SPI_REQ *pSMB = NULL;
2853 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2854 char *data_offset;
2855 int name_len;
2856 int name_len_target;
2857 int rc = 0;
2858 int bytes_returned = 0;
2859 __u16 params, param_offset, offset, byte_count;
2860
Joe Perchesb6b38f72010-04-21 03:50:45 +00002861 cFYI(1, "In Create Hard link Unix style");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002862createHardLinkRetry:
2863 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2864 (void **) &pSMBr);
2865 if (rc)
2866 return rc;
2867
2868 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002869 name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, toName,
2870 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002871 name_len++; /* trailing null */
2872 name_len *= 2;
2873
Steve French50c2f752007-07-13 00:33:32 +00002874 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002875 name_len = strnlen(toName, PATH_MAX);
2876 name_len++; /* trailing null */
2877 strncpy(pSMB->FileName, toName, name_len);
2878 }
2879 params = 6 + name_len;
2880 pSMB->MaxSetupCount = 0;
2881 pSMB->Reserved = 0;
2882 pSMB->Flags = 0;
2883 pSMB->Timeout = 0;
2884 pSMB->Reserved2 = 0;
2885 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002886 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002887 offset = param_offset + params;
2888
2889 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2890 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2891 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06002892 cifsConvertToUTF16((__le16 *) data_offset, fromName,
2893 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002894 name_len_target++; /* trailing null */
2895 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002896 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002897 name_len_target = strnlen(fromName, PATH_MAX);
2898 name_len_target++; /* trailing null */
2899 strncpy(data_offset, fromName, name_len_target);
2900 }
2901
2902 pSMB->MaxParameterCount = cpu_to_le16(2);
2903 /* BB find exact max on data count below from sess*/
2904 pSMB->MaxDataCount = cpu_to_le16(1000);
2905 pSMB->SetupCount = 1;
2906 pSMB->Reserved3 = 0;
2907 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2908 byte_count = 3 /* pad */ + params + name_len_target;
2909 pSMB->ParameterCount = cpu_to_le16(params);
2910 pSMB->TotalParameterCount = pSMB->ParameterCount;
2911 pSMB->DataCount = cpu_to_le16(name_len_target);
2912 pSMB->TotalDataCount = pSMB->DataCount;
2913 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2914 pSMB->DataOffset = cpu_to_le16(offset);
2915 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2916 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002917 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002918 pSMB->ByteCount = cpu_to_le16(byte_count);
2919 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2920 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002921 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002922 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002923 cFYI(1, "Send error in SetPathInfo (hard link) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002924
2925 cifs_buf_release(pSMB);
2926 if (rc == -EAGAIN)
2927 goto createHardLinkRetry;
2928
2929 return rc;
2930}
2931
2932int
Steve French96daf2b2011-05-27 04:34:02 +00002933CIFSCreateHardLink(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002934 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002935 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002936{
2937 int rc = 0;
2938 NT_RENAME_REQ *pSMB = NULL;
2939 RENAME_RSP *pSMBr = NULL;
2940 int bytes_returned;
2941 int name_len, name_len2;
2942 __u16 count;
2943
Joe Perchesb6b38f72010-04-21 03:50:45 +00002944 cFYI(1, "In CIFSCreateHardLink");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002945winCreateHardLinkRetry:
2946
2947 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2948 (void **) &pSMBr);
2949 if (rc)
2950 return rc;
2951
2952 pSMB->SearchAttributes =
2953 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2954 ATTR_DIRECTORY);
2955 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2956 pSMB->ClusterCount = 0;
2957
2958 pSMB->BufferFormat = 0x04;
2959
2960 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2961 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06002962 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, fromName,
2963 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002964 name_len++; /* trailing null */
2965 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05002966
2967 /* protocol specifies ASCII buffer format (0x04) for unicode */
2968 pSMB->OldFileName[name_len] = 0x04;
2969 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002970 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002971 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2972 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002973 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2974 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002975 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002976 name_len = strnlen(fromName, PATH_MAX);
2977 name_len++; /* trailing null */
2978 strncpy(pSMB->OldFileName, fromName, name_len);
2979 name_len2 = strnlen(toName, PATH_MAX);
2980 name_len2++; /* trailing null */
2981 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2982 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2983 name_len2++; /* trailing null */
2984 name_len2++; /* signature byte */
2985 }
2986
2987 count = 1 /* string type byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002988 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002989 pSMB->ByteCount = cpu_to_le16(count);
2990
2991 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2992 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002993 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002994 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002995 cFYI(1, "Send error in hard link (NT rename) = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00002996
Linus Torvalds1da177e2005-04-16 15:20:36 -07002997 cifs_buf_release(pSMB);
2998 if (rc == -EAGAIN)
2999 goto winCreateHardLinkRetry;
3000
3001 return rc;
3002}
3003
3004int
Steve French96daf2b2011-05-27 04:34:02 +00003005CIFSSMBUnixQuerySymLink(const int xid, struct cifs_tcon *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04003006 const unsigned char *searchName, char **symlinkinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003007 const struct nls_table *nls_codepage)
3008{
3009/* SMB_QUERY_FILE_UNIX_LINK */
3010 TRANSACTION2_QPI_REQ *pSMB = NULL;
3011 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3012 int rc = 0;
3013 int bytes_returned;
3014 int name_len;
3015 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04003016 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003017
Joe Perchesb6b38f72010-04-21 03:50:45 +00003018 cFYI(1, "In QPathSymLinkInfo (Unix) for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003019
3020querySymLinkRetry:
3021 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3022 (void **) &pSMBr);
3023 if (rc)
3024 return rc;
3025
3026 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3027 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003028 cifs_strtoUTF16((__le16 *) pSMB->FileName, searchName,
3029 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003030 name_len++; /* trailing null */
3031 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003032 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003033 name_len = strnlen(searchName, PATH_MAX);
3034 name_len++; /* trailing null */
3035 strncpy(pSMB->FileName, searchName, name_len);
3036 }
3037
3038 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3039 pSMB->TotalDataCount = 0;
3040 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04003041 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003042 pSMB->MaxSetupCount = 0;
3043 pSMB->Reserved = 0;
3044 pSMB->Flags = 0;
3045 pSMB->Timeout = 0;
3046 pSMB->Reserved2 = 0;
3047 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003048 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003049 pSMB->DataCount = 0;
3050 pSMB->DataOffset = 0;
3051 pSMB->SetupCount = 1;
3052 pSMB->Reserved3 = 0;
3053 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3054 byte_count = params + 1 /* pad */ ;
3055 pSMB->TotalParameterCount = cpu_to_le16(params);
3056 pSMB->ParameterCount = pSMB->TotalParameterCount;
3057 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
3058 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003059 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003060 pSMB->ByteCount = cpu_to_le16(byte_count);
3061
3062 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3063 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3064 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003065 cFYI(1, "Send error in QuerySymLinkInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003066 } else {
3067 /* decode response */
3068
3069 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003070 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003071 if (rc || get_bcc(&pSMBr->hdr) < 2)
Jeff Layton460b9692009-04-30 07:17:56 -04003072 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003073 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00003074 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04003075 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003076
Jeff Layton460b9692009-04-30 07:17:56 -04003077 data_start = ((char *) &pSMBr->hdr.Protocol) +
3078 le16_to_cpu(pSMBr->t2.DataOffset);
3079
Steve French0e0d2cf2009-05-01 05:27:32 +00003080 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3081 is_unicode = true;
3082 else
3083 is_unicode = false;
3084
Steve French737b7582005-04-28 22:41:06 -07003085 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchacbbb762012-01-18 22:32:33 -06003086 *symlinkinfo = cifs_strndup_from_utf16(data_start,
3087 count, is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04003088 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04003089 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003090 }
3091 }
3092 cifs_buf_release(pSMB);
3093 if (rc == -EAGAIN)
3094 goto querySymLinkRetry;
3095 return rc;
3096}
3097
Steve Frenchc52a9552011-02-24 06:16:22 +00003098#ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL
3099/*
3100 * Recent Windows versions now create symlinks more frequently
3101 * and they use the "reparse point" mechanism below. We can of course
3102 * do symlinks nicely to Samba and other servers which support the
3103 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
3104 * "MF" symlinks optionally, but for recent Windows we really need to
3105 * reenable the code below and fix the cifs_symlink callers to handle this.
3106 * In the interim this code has been moved to its own config option so
3107 * it is not compiled in by default until callers fixed up and more tested.
3108 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003109int
Steve French96daf2b2011-05-27 04:34:02 +00003110CIFSSMBQueryReparseLinkInfo(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003111 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00003112 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003113 const struct nls_table *nls_codepage)
3114{
3115 int rc = 0;
3116 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00003117 struct smb_com_transaction_ioctl_req *pSMB;
3118 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003119
Joe Perchesb6b38f72010-04-21 03:50:45 +00003120 cFYI(1, "In Windows reparse style QueryLink for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003121 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3122 (void **) &pSMBr);
3123 if (rc)
3124 return rc;
3125
3126 pSMB->TotalParameterCount = 0 ;
3127 pSMB->TotalDataCount = 0;
3128 pSMB->MaxParameterCount = cpu_to_le32(2);
3129 /* BB find exact data count max from sess structure BB */
Jeff Laytonc974bef2011-10-11 06:41:32 -04003130 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003131 pSMB->MaxSetupCount = 4;
3132 pSMB->Reserved = 0;
3133 pSMB->ParameterOffset = 0;
3134 pSMB->DataCount = 0;
3135 pSMB->DataOffset = 0;
3136 pSMB->SetupCount = 4;
3137 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
3138 pSMB->ParameterCount = pSMB->TotalParameterCount;
3139 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
3140 pSMB->IsFsctl = 1; /* FSCTL */
3141 pSMB->IsRootFlag = 0;
3142 pSMB->Fid = fid; /* file handle always le */
3143 pSMB->ByteCount = 0;
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 QueryReparseLinkInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003149 } else { /* decode response */
3150 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
3151 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
Jeff Layton820a8032011-05-04 08:05:26 -04003152 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
3153 /* BB also check enough total bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003154 rc = -EIO; /* bad smb */
Steve Frenchafe48c32009-05-02 05:25:46 +00003155 goto qreparse_out;
3156 }
3157 if (data_count && (data_count < 2048)) {
3158 char *end_of_smb = 2 /* sizeof byte count */ +
Jeff Layton820a8032011-05-04 08:05:26 -04003159 get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003160
Steve Frenchafe48c32009-05-02 05:25:46 +00003161 struct reparse_data *reparse_buf =
Steve French50c2f752007-07-13 00:33:32 +00003162 (struct reparse_data *)
3163 ((char *)&pSMBr->hdr.Protocol
3164 + data_offset);
Steve Frenchafe48c32009-05-02 05:25:46 +00003165 if ((char *)reparse_buf >= end_of_smb) {
3166 rc = -EIO;
3167 goto qreparse_out;
3168 }
3169 if ((reparse_buf->LinkNamesBuf +
3170 reparse_buf->TargetNameOffset +
3171 reparse_buf->TargetNameLen) > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003172 cFYI(1, "reparse buf beyond SMB");
Steve Frenchafe48c32009-05-02 05:25:46 +00003173 rc = -EIO;
3174 goto qreparse_out;
3175 }
Steve French50c2f752007-07-13 00:33:32 +00003176
Steve Frenchafe48c32009-05-02 05:25:46 +00003177 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3178 cifs_from_ucs2(symlinkinfo, (__le16 *)
Steve French50c2f752007-07-13 00:33:32 +00003179 (reparse_buf->LinkNamesBuf +
3180 reparse_buf->TargetNameOffset),
Steve Frenchafe48c32009-05-02 05:25:46 +00003181 buflen,
3182 reparse_buf->TargetNameLen,
3183 nls_codepage, 0);
3184 } else { /* ASCII names */
3185 strncpy(symlinkinfo,
3186 reparse_buf->LinkNamesBuf +
3187 reparse_buf->TargetNameOffset,
3188 min_t(const int, buflen,
3189 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003190 }
Steve Frenchafe48c32009-05-02 05:25:46 +00003191 } else {
3192 rc = -EIO;
Joe Perchesb6b38f72010-04-21 03:50:45 +00003193 cFYI(1, "Invalid return data count on "
3194 "get reparse info ioctl");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003195 }
Steve Frenchafe48c32009-05-02 05:25:46 +00003196 symlinkinfo[buflen] = 0; /* just in case so the caller
3197 does not go off the end of the buffer */
Joe Perchesb6b38f72010-04-21 03:50:45 +00003198 cFYI(1, "readlink result - %s", symlinkinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003199 }
Steve French989c7e52009-05-02 05:32:20 +00003200
Linus Torvalds1da177e2005-04-16 15:20:36 -07003201qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07003202 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003203
3204 /* Note: On -EAGAIN error only caller can retry on handle based calls
3205 since file handle passed in no longer valid */
3206
3207 return rc;
3208}
Steve Frenchc52a9552011-02-24 06:16:22 +00003209#endif /* CIFS_SYMLINK_EXPERIMENTAL */ /* BB temporarily unused */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003210
3211#ifdef CONFIG_CIFS_POSIX
3212
3213/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00003214static void cifs_convert_ace(posix_acl_xattr_entry *ace,
3215 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003216{
3217 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08003218 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
3219 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
3220 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesb6b38f72010-04-21 03:50:45 +00003221 /* cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003222
3223 return;
3224}
3225
3226/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00003227static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
3228 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003229{
3230 int size = 0;
3231 int i;
3232 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00003233 struct cifs_posix_ace *pACE;
3234 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
3235 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003236
3237 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
3238 return -EOPNOTSUPP;
3239
Steve French790fe572007-07-07 19:25:05 +00003240 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003241 count = le16_to_cpu(cifs_acl->access_entry_count);
3242 pACE = &cifs_acl->ace_array[0];
3243 size = sizeof(struct cifs_posix_acl);
3244 size += sizeof(struct cifs_posix_ace) * count;
3245 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003246 if (size_of_data_area < size) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003247 cFYI(1, "bad CIFS POSIX ACL size %d vs. %d",
3248 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003249 return -EINVAL;
3250 }
Steve French790fe572007-07-07 19:25:05 +00003251 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003252 count = le16_to_cpu(cifs_acl->access_entry_count);
3253 size = sizeof(struct cifs_posix_acl);
3254 size += sizeof(struct cifs_posix_ace) * count;
3255/* skip past access ACEs to get to default ACEs */
3256 pACE = &cifs_acl->ace_array[count];
3257 count = le16_to_cpu(cifs_acl->default_entry_count);
3258 size += sizeof(struct cifs_posix_ace) * count;
3259 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003260 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003261 return -EINVAL;
3262 } else {
3263 /* illegal type */
3264 return -EINVAL;
3265 }
3266
3267 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00003268 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00003269 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00003270 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003271 return -ERANGE;
3272 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08003273 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00003274 for (i = 0; i < count ; i++) {
3275 cifs_convert_ace(&local_acl->a_entries[i], pACE);
3276 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003277 }
3278 }
3279 return size;
3280}
3281
Steve French50c2f752007-07-13 00:33:32 +00003282static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
3283 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003284{
3285 __u16 rc = 0; /* 0 = ACL converted ok */
3286
Steve Frenchff7feac2005-11-15 16:45:16 -08003287 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
3288 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003289 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00003290 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003291 /* Probably no need to le convert -1 on any arch but can not hurt */
3292 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00003293 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08003294 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesb6b38f72010-04-21 03:50:45 +00003295 /*cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id);*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003296 return rc;
3297}
3298
3299/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00003300static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
3301 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003302{
3303 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00003304 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
3305 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003306 int count;
3307 int i;
3308
Steve French790fe572007-07-07 19:25:05 +00003309 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003310 return 0;
3311
3312 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesb6b38f72010-04-21 03:50:45 +00003313 cFYI(1, "setting acl with %d entries from buf of length %d and "
Steve French63135e02007-07-17 17:34:02 +00003314 "version of %d",
Joe Perchesb6b38f72010-04-21 03:50:45 +00003315 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00003316 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003317 cFYI(1, "unknown POSIX ACL version %d",
3318 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003319 return 0;
3320 }
3321 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00003322 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08003323 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00003324 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08003325 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003326 else {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003327 cFYI(1, "unknown ACL type %d", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003328 return 0;
3329 }
Steve French50c2f752007-07-13 00:33:32 +00003330 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003331 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
3332 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00003333 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003334 /* ACE not converted */
3335 break;
3336 }
3337 }
Steve French790fe572007-07-07 19:25:05 +00003338 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003339 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
3340 rc += sizeof(struct cifs_posix_acl);
3341 /* BB add check to make sure ACL does not overflow SMB */
3342 }
3343 return rc;
3344}
3345
3346int
Steve French96daf2b2011-05-27 04:34:02 +00003347CIFSSMBGetPosixACL(const int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003348 const unsigned char *searchName,
3349 char *acl_inf, const int buflen, const int acl_type,
3350 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003351{
3352/* SMB_QUERY_POSIX_ACL */
3353 TRANSACTION2_QPI_REQ *pSMB = NULL;
3354 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3355 int rc = 0;
3356 int bytes_returned;
3357 int name_len;
3358 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00003359
Joe Perchesb6b38f72010-04-21 03:50:45 +00003360 cFYI(1, "In GetPosixACL (Unix) for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003361
3362queryAclRetry:
3363 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3364 (void **) &pSMBr);
3365 if (rc)
3366 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003367
Linus Torvalds1da177e2005-04-16 15:20:36 -07003368 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3369 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003370 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3371 searchName, PATH_MAX, nls_codepage,
3372 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003373 name_len++; /* trailing null */
3374 name_len *= 2;
3375 pSMB->FileName[name_len] = 0;
3376 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00003377 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003378 name_len = strnlen(searchName, PATH_MAX);
3379 name_len++; /* trailing null */
3380 strncpy(pSMB->FileName, searchName, name_len);
3381 }
3382
3383 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3384 pSMB->TotalDataCount = 0;
3385 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00003386 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003387 pSMB->MaxDataCount = cpu_to_le16(4000);
3388 pSMB->MaxSetupCount = 0;
3389 pSMB->Reserved = 0;
3390 pSMB->Flags = 0;
3391 pSMB->Timeout = 0;
3392 pSMB->Reserved2 = 0;
3393 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003394 offsetof(struct smb_com_transaction2_qpi_req,
3395 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003396 pSMB->DataCount = 0;
3397 pSMB->DataOffset = 0;
3398 pSMB->SetupCount = 1;
3399 pSMB->Reserved3 = 0;
3400 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3401 byte_count = params + 1 /* pad */ ;
3402 pSMB->TotalParameterCount = cpu_to_le16(params);
3403 pSMB->ParameterCount = pSMB->TotalParameterCount;
3404 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
3405 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003406 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003407 pSMB->ByteCount = cpu_to_le16(byte_count);
3408
3409 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3410 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08003411 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003412 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003413 cFYI(1, "Send error in Query POSIX ACL = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003414 } else {
3415 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00003416
Linus Torvalds1da177e2005-04-16 15:20:36 -07003417 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003418 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003419 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003420 rc = -EIO; /* bad smb */
3421 else {
3422 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3423 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3424 rc = cifs_copy_posix_acl(acl_inf,
3425 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00003426 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003427 }
3428 }
3429 cifs_buf_release(pSMB);
3430 if (rc == -EAGAIN)
3431 goto queryAclRetry;
3432 return rc;
3433}
3434
3435int
Steve French96daf2b2011-05-27 04:34:02 +00003436CIFSSMBSetPosixACL(const int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003437 const unsigned char *fileName,
3438 const char *local_acl, const int buflen,
3439 const int acl_type,
3440 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003441{
3442 struct smb_com_transaction2_spi_req *pSMB = NULL;
3443 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3444 char *parm_data;
3445 int name_len;
3446 int rc = 0;
3447 int bytes_returned = 0;
3448 __u16 params, byte_count, data_count, param_offset, offset;
3449
Joe Perchesb6b38f72010-04-21 03:50:45 +00003450 cFYI(1, "In SetPosixACL (Unix) for path %s", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003451setAclRetry:
3452 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003453 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003454 if (rc)
3455 return rc;
3456 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3457 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003458 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
3459 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003460 name_len++; /* trailing null */
3461 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003462 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003463 name_len = strnlen(fileName, PATH_MAX);
3464 name_len++; /* trailing null */
3465 strncpy(pSMB->FileName, fileName, name_len);
3466 }
3467 params = 6 + name_len;
3468 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003469 /* BB find max SMB size from sess */
3470 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003471 pSMB->MaxSetupCount = 0;
3472 pSMB->Reserved = 0;
3473 pSMB->Flags = 0;
3474 pSMB->Timeout = 0;
3475 pSMB->Reserved2 = 0;
3476 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003477 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003478 offset = param_offset + params;
3479 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
3480 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3481
3482 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00003483 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003484
Steve French790fe572007-07-07 19:25:05 +00003485 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003486 rc = -EOPNOTSUPP;
3487 goto setACLerrorExit;
3488 }
3489 pSMB->DataOffset = cpu_to_le16(offset);
3490 pSMB->SetupCount = 1;
3491 pSMB->Reserved3 = 0;
3492 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3493 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
3494 byte_count = 3 /* pad */ + params + data_count;
3495 pSMB->DataCount = cpu_to_le16(data_count);
3496 pSMB->TotalDataCount = pSMB->DataCount;
3497 pSMB->ParameterCount = cpu_to_le16(params);
3498 pSMB->TotalParameterCount = pSMB->ParameterCount;
3499 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003500 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003501 pSMB->ByteCount = cpu_to_le16(byte_count);
3502 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003503 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003504 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003505 cFYI(1, "Set POSIX ACL returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003506
3507setACLerrorExit:
3508 cifs_buf_release(pSMB);
3509 if (rc == -EAGAIN)
3510 goto setAclRetry;
3511 return rc;
3512}
3513
Steve Frenchf654bac2005-04-28 22:41:04 -07003514/* BB fix tabs in this function FIXME BB */
3515int
Steve French96daf2b2011-05-27 04:34:02 +00003516CIFSGetExtAttr(const int xid, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00003517 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07003518{
Steve French50c2f752007-07-13 00:33:32 +00003519 int rc = 0;
3520 struct smb_t2_qfi_req *pSMB = NULL;
3521 struct smb_t2_qfi_rsp *pSMBr = NULL;
3522 int bytes_returned;
3523 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07003524
Joe Perchesb6b38f72010-04-21 03:50:45 +00003525 cFYI(1, "In GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00003526 if (tcon == NULL)
3527 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07003528
3529GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003530 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3531 (void **) &pSMBr);
3532 if (rc)
3533 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003534
Steve Frenchad7a2922008-02-07 23:25:02 +00003535 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003536 pSMB->t2.TotalDataCount = 0;
3537 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3538 /* BB find exact max data count below from sess structure BB */
3539 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3540 pSMB->t2.MaxSetupCount = 0;
3541 pSMB->t2.Reserved = 0;
3542 pSMB->t2.Flags = 0;
3543 pSMB->t2.Timeout = 0;
3544 pSMB->t2.Reserved2 = 0;
3545 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3546 Fid) - 4);
3547 pSMB->t2.DataCount = 0;
3548 pSMB->t2.DataOffset = 0;
3549 pSMB->t2.SetupCount = 1;
3550 pSMB->t2.Reserved3 = 0;
3551 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3552 byte_count = params + 1 /* pad */ ;
3553 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3554 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3555 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3556 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003557 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003558 inc_rfc1001_len(pSMB, byte_count);
Steve French790fe572007-07-07 19:25:05 +00003559 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003560
Steve French790fe572007-07-07 19:25:05 +00003561 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3562 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3563 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003564 cFYI(1, "error %d in GetExtAttr", rc);
Steve French790fe572007-07-07 19:25:05 +00003565 } else {
3566 /* decode response */
3567 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003568 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003569 if (rc || get_bcc(&pSMBr->hdr) < 2)
Steve French790fe572007-07-07 19:25:05 +00003570 /* If rc should we check for EOPNOSUPP and
3571 disable the srvino flag? or in caller? */
3572 rc = -EIO; /* bad smb */
3573 else {
3574 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3575 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3576 struct file_chattr_info *pfinfo;
3577 /* BB Do we need a cast or hash here ? */
3578 if (count != 16) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003579 cFYI(1, "Illegal size ret in GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00003580 rc = -EIO;
3581 goto GetExtAttrOut;
3582 }
3583 pfinfo = (struct file_chattr_info *)
3584 (data_offset + (char *) &pSMBr->hdr.Protocol);
3585 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003586 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003587 }
3588 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003589GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003590 cifs_buf_release(pSMB);
3591 if (rc == -EAGAIN)
3592 goto GetExtAttrRetry;
3593 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003594}
3595
Steve Frenchf654bac2005-04-28 22:41:04 -07003596#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003597
Jeff Layton79df1ba2010-12-06 12:52:08 -05003598#ifdef CONFIG_CIFS_ACL
3599/*
3600 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3601 * all NT TRANSACTS that we init here have total parm and data under about 400
3602 * bytes (to fit in small cifs buffer size), which is the case so far, it
3603 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3604 * returned setup area) and MaxParameterCount (returned parms size) must be set
3605 * by caller
3606 */
3607static int
3608smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French96daf2b2011-05-27 04:34:02 +00003609 const int parm_len, struct cifs_tcon *tcon,
Jeff Layton79df1ba2010-12-06 12:52:08 -05003610 void **ret_buf)
3611{
3612 int rc;
3613 __u32 temp_offset;
3614 struct smb_com_ntransact_req *pSMB;
3615
3616 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3617 (void **)&pSMB);
3618 if (rc)
3619 return rc;
3620 *ret_buf = (void *)pSMB;
3621 pSMB->Reserved = 0;
3622 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3623 pSMB->TotalDataCount = 0;
Jeff Laytonc974bef2011-10-11 06:41:32 -04003624 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003625 pSMB->ParameterCount = pSMB->TotalParameterCount;
3626 pSMB->DataCount = pSMB->TotalDataCount;
3627 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3628 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3629 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3630 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3631 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3632 pSMB->SubCommand = cpu_to_le16(sub_command);
3633 return 0;
3634}
3635
3636static int
3637validate_ntransact(char *buf, char **ppparm, char **ppdata,
3638 __u32 *pparmlen, __u32 *pdatalen)
3639{
3640 char *end_of_smb;
3641 __u32 data_count, data_offset, parm_count, parm_offset;
3642 struct smb_com_ntransact_rsp *pSMBr;
Jeff Layton820a8032011-05-04 08:05:26 -04003643 u16 bcc;
Jeff Layton79df1ba2010-12-06 12:52:08 -05003644
3645 *pdatalen = 0;
3646 *pparmlen = 0;
3647
3648 if (buf == NULL)
3649 return -EINVAL;
3650
3651 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3652
Jeff Layton820a8032011-05-04 08:05:26 -04003653 bcc = get_bcc(&pSMBr->hdr);
3654 end_of_smb = 2 /* sizeof byte count */ + bcc +
Jeff Layton79df1ba2010-12-06 12:52:08 -05003655 (char *)&pSMBr->ByteCount;
3656
3657 data_offset = le32_to_cpu(pSMBr->DataOffset);
3658 data_count = le32_to_cpu(pSMBr->DataCount);
3659 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3660 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3661
3662 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3663 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3664
3665 /* should we also check that parm and data areas do not overlap? */
3666 if (*ppparm > end_of_smb) {
3667 cFYI(1, "parms start after end of smb");
3668 return -EINVAL;
3669 } else if (parm_count + *ppparm > end_of_smb) {
3670 cFYI(1, "parm end after end of smb");
3671 return -EINVAL;
3672 } else if (*ppdata > end_of_smb) {
3673 cFYI(1, "data starts after end of smb");
3674 return -EINVAL;
3675 } else if (data_count + *ppdata > end_of_smb) {
3676 cFYI(1, "data %p + count %d (%p) past smb end %p start %p",
3677 *ppdata, data_count, (data_count + *ppdata),
3678 end_of_smb, pSMBr);
3679 return -EINVAL;
Jeff Layton820a8032011-05-04 08:05:26 -04003680 } else if (parm_count + data_count > bcc) {
Jeff Layton79df1ba2010-12-06 12:52:08 -05003681 cFYI(1, "parm count and data count larger than SMB");
3682 return -EINVAL;
3683 }
3684 *pdatalen = data_count;
3685 *pparmlen = parm_count;
3686 return 0;
3687}
3688
Steve French0a4b92c2006-01-12 15:44:21 -08003689/* Get Security Descriptor (by handle) from remote server for a file or dir */
3690int
Steve French96daf2b2011-05-27 04:34:02 +00003691CIFSSMBGetCIFSACL(const int xid, struct cifs_tcon *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003692 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003693{
3694 int rc = 0;
3695 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003696 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003697 struct kvec iov[1];
3698
Joe Perchesb6b38f72010-04-21 03:50:45 +00003699 cFYI(1, "GetCifsACL");
Steve French0a4b92c2006-01-12 15:44:21 -08003700
Steve French630f3f0c2007-10-25 21:17:17 +00003701 *pbuflen = 0;
3702 *acl_inf = NULL;
3703
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003704 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003705 8 /* parm len */, tcon, (void **) &pSMB);
3706 if (rc)
3707 return rc;
3708
3709 pSMB->MaxParameterCount = cpu_to_le32(4);
3710 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3711 pSMB->MaxSetupCount = 0;
3712 pSMB->Fid = fid; /* file handle always le */
3713 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3714 CIFS_ACL_DACL);
3715 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003716 inc_rfc1001_len(pSMB, 11);
Steve French0a4b92c2006-01-12 15:44:21 -08003717 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003718 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French0a4b92c2006-01-12 15:44:21 -08003719
Steve Frencha761ac52007-10-18 21:45:27 +00003720 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Jeff Layton77499812011-01-11 07:24:23 -05003721 0);
Steve French0a4b92c2006-01-12 15:44:21 -08003722 cifs_stats_inc(&tcon->num_acl_get);
3723 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003724 cFYI(1, "Send error in QuerySecDesc = %d", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08003725 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003726 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003727 __u32 parm_len;
3728 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003729 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003730 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003731
3732/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003733 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003734 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003735 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003736 goto qsec_out;
3737 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3738
Joe Perchesb6b38f72010-04-21 03:50:45 +00003739 cFYI(1, "smb %p parm %p data %p", pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08003740
3741 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3742 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003743 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003744 goto qsec_out;
3745 }
3746
3747/* BB check that data area is minimum length and as big as acl_len */
3748
Steve Frenchaf6f4612007-10-16 18:40:37 +00003749 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003750 if (acl_len != *pbuflen) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003751 cERROR(1, "acl length %d does not match %d",
3752 acl_len, *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003753 if (*pbuflen > acl_len)
3754 *pbuflen = acl_len;
3755 }
Steve French0a4b92c2006-01-12 15:44:21 -08003756
Steve French630f3f0c2007-10-25 21:17:17 +00003757 /* check if buffer is big enough for the acl
3758 header followed by the smallest SID */
3759 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3760 (*pbuflen >= 64 * 1024)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003761 cERROR(1, "bad acl length %d", *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003762 rc = -EINVAL;
3763 *pbuflen = 0;
3764 } else {
3765 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3766 if (*acl_inf == NULL) {
3767 *pbuflen = 0;
3768 rc = -ENOMEM;
3769 }
3770 memcpy(*acl_inf, pdata, *pbuflen);
3771 }
Steve French0a4b92c2006-01-12 15:44:21 -08003772 }
3773qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003774 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003775 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003776 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003777 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003778/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003779 return rc;
3780}
Steve French97837582007-12-31 07:47:21 +00003781
3782int
Steve French96daf2b2011-05-27 04:34:02 +00003783CIFSSMBSetCIFSACL(const int xid, struct cifs_tcon *tcon, __u16 fid,
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003784 struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
Steve French97837582007-12-31 07:47:21 +00003785{
3786 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3787 int rc = 0;
3788 int bytes_returned = 0;
3789 SET_SEC_DESC_REQ *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003790 void *pSMBr;
Steve French97837582007-12-31 07:47:21 +00003791
3792setCifsAclRetry:
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003793 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, &pSMBr);
Steve French97837582007-12-31 07:47:21 +00003794 if (rc)
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003795 return rc;
Steve French97837582007-12-31 07:47:21 +00003796
3797 pSMB->MaxSetupCount = 0;
3798 pSMB->Reserved = 0;
3799
3800 param_count = 8;
3801 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3802 data_count = acllen;
3803 data_offset = param_offset + param_count;
3804 byte_count = 3 /* pad */ + param_count;
3805
3806 pSMB->DataCount = cpu_to_le32(data_count);
3807 pSMB->TotalDataCount = pSMB->DataCount;
3808 pSMB->MaxParameterCount = cpu_to_le32(4);
3809 pSMB->MaxDataCount = cpu_to_le32(16384);
3810 pSMB->ParameterCount = cpu_to_le32(param_count);
3811 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3812 pSMB->TotalParameterCount = pSMB->ParameterCount;
3813 pSMB->DataOffset = cpu_to_le32(data_offset);
3814 pSMB->SetupCount = 0;
3815 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3816 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3817
3818 pSMB->Fid = fid; /* file handle always le */
3819 pSMB->Reserved2 = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003820 pSMB->AclFlags = cpu_to_le32(aclflag);
Steve French97837582007-12-31 07:47:21 +00003821
3822 if (pntsd && acllen) {
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003823 memcpy((char *)pSMBr + offsetof(struct smb_hdr, Protocol) +
3824 data_offset, pntsd, acllen);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003825 inc_rfc1001_len(pSMB, byte_count + data_count);
Steve French97837582007-12-31 07:47:21 +00003826 } else
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003827 inc_rfc1001_len(pSMB, byte_count);
Steve French97837582007-12-31 07:47:21 +00003828
3829 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3830 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3831
Joe Perchesb6b38f72010-04-21 03:50:45 +00003832 cFYI(1, "SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00003833 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003834 cFYI(1, "Set CIFS ACL returned %d", rc);
Steve French97837582007-12-31 07:47:21 +00003835 cifs_buf_release(pSMB);
3836
3837 if (rc == -EAGAIN)
3838 goto setCifsAclRetry;
3839
3840 return (rc);
3841}
3842
Jeff Layton79df1ba2010-12-06 12:52:08 -05003843#endif /* CONFIG_CIFS_ACL */
Steve French0a4b92c2006-01-12 15:44:21 -08003844
Steve French6b8edfe2005-08-23 20:26:03 -07003845/* Legacy Query Path Information call for lookup to old servers such
3846 as Win9x/WinME */
Steve French96daf2b2011-05-27 04:34:02 +00003847int SMBQueryInformation(const int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003848 const unsigned char *searchName,
3849 FILE_ALL_INFO *pFinfo,
3850 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003851{
Steve Frenchad7a2922008-02-07 23:25:02 +00003852 QUERY_INFORMATION_REQ *pSMB;
3853 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003854 int rc = 0;
3855 int bytes_returned;
3856 int name_len;
3857
Joe Perchesb6b38f72010-04-21 03:50:45 +00003858 cFYI(1, "In SMBQPath path %s", searchName);
Steve French6b8edfe2005-08-23 20:26:03 -07003859QInfRetry:
3860 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003861 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003862 if (rc)
3863 return rc;
3864
3865 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3866 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003867 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3868 searchName, PATH_MAX, nls_codepage,
3869 remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003870 name_len++; /* trailing null */
3871 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003872 } else {
Steve French6b8edfe2005-08-23 20:26:03 -07003873 name_len = strnlen(searchName, PATH_MAX);
3874 name_len++; /* trailing null */
3875 strncpy(pSMB->FileName, searchName, name_len);
3876 }
3877 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003878 name_len++; /* account for buffer type byte */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003879 inc_rfc1001_len(pSMB, (__u16)name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07003880 pSMB->ByteCount = cpu_to_le16(name_len);
3881
3882 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003883 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003884 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003885 cFYI(1, "Send error in QueryInfo = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00003886 } else if (pFinfo) {
Steve French1bd5bbc2006-09-28 03:35:57 +00003887 struct timespec ts;
3888 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00003889
3890 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003891 /* BB FIXME - add time zone adjustment BB */
Steve French6b8edfe2005-08-23 20:26:03 -07003892 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003893 ts.tv_nsec = 0;
3894 ts.tv_sec = time;
3895 /* decode time fields */
Al Viro733f99a2006-10-14 16:48:26 +01003896 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
Steve French1bd5bbc2006-09-28 03:35:57 +00003897 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3898 pFinfo->LastAccessTime = 0;
Steve French70ca7342005-09-22 16:32:06 -07003899 pFinfo->AllocationSize =
3900 cpu_to_le64(le32_to_cpu(pSMBr->size));
3901 pFinfo->EndOfFile = pFinfo->AllocationSize;
3902 pFinfo->Attributes =
3903 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003904 } else
3905 rc = -EIO; /* bad buffer passed in */
3906
3907 cifs_buf_release(pSMB);
3908
3909 if (rc == -EAGAIN)
3910 goto QInfRetry;
3911
3912 return rc;
3913}
3914
Jeff Laytonbcd53572010-02-12 07:44:16 -05003915int
Steve French96daf2b2011-05-27 04:34:02 +00003916CIFSSMBQFileInfo(const int xid, struct cifs_tcon *tcon,
Jeff Laytonbcd53572010-02-12 07:44:16 -05003917 u16 netfid, FILE_ALL_INFO *pFindData)
3918{
3919 struct smb_t2_qfi_req *pSMB = NULL;
3920 struct smb_t2_qfi_rsp *pSMBr = NULL;
3921 int rc = 0;
3922 int bytes_returned;
3923 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07003924
Jeff Laytonbcd53572010-02-12 07:44:16 -05003925QFileInfoRetry:
3926 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3927 (void **) &pSMBr);
3928 if (rc)
3929 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07003930
Jeff Laytonbcd53572010-02-12 07:44:16 -05003931 params = 2 /* level */ + 2 /* fid */;
3932 pSMB->t2.TotalDataCount = 0;
3933 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3934 /* BB find exact max data count below from sess structure BB */
3935 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3936 pSMB->t2.MaxSetupCount = 0;
3937 pSMB->t2.Reserved = 0;
3938 pSMB->t2.Flags = 0;
3939 pSMB->t2.Timeout = 0;
3940 pSMB->t2.Reserved2 = 0;
3941 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3942 Fid) - 4);
3943 pSMB->t2.DataCount = 0;
3944 pSMB->t2.DataOffset = 0;
3945 pSMB->t2.SetupCount = 1;
3946 pSMB->t2.Reserved3 = 0;
3947 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3948 byte_count = params + 1 /* pad */ ;
3949 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3950 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3951 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3952 pSMB->Pad = 0;
3953 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003954 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003955
3956 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3957 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3958 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00003959 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003960 } else { /* decode response */
3961 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3962
3963 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3964 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04003965 else if (get_bcc(&pSMBr->hdr) < 40)
Jeff Laytonbcd53572010-02-12 07:44:16 -05003966 rc = -EIO; /* bad smb */
3967 else if (pFindData) {
3968 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3969 memcpy((char *) pFindData,
3970 (char *) &pSMBr->hdr.Protocol +
3971 data_offset, sizeof(FILE_ALL_INFO));
3972 } else
3973 rc = -ENOMEM;
3974 }
3975 cifs_buf_release(pSMB);
3976 if (rc == -EAGAIN)
3977 goto QFileInfoRetry;
3978
3979 return rc;
3980}
Steve French6b8edfe2005-08-23 20:26:03 -07003981
Linus Torvalds1da177e2005-04-16 15:20:36 -07003982int
Steve French96daf2b2011-05-27 04:34:02 +00003983CIFSSMBQPathInfo(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003984 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003985 FILE_ALL_INFO *pFindData,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003986 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003987 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003988{
3989/* level 263 SMB_QUERY_FILE_ALL_INFO */
3990 TRANSACTION2_QPI_REQ *pSMB = NULL;
3991 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3992 int rc = 0;
3993 int bytes_returned;
3994 int name_len;
3995 __u16 params, byte_count;
3996
Joe Perchesb6b38f72010-04-21 03:50:45 +00003997/* cFYI(1, "In QPathInfo path %s", searchName); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003998QPathInfoRetry:
3999 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4000 (void **) &pSMBr);
4001 if (rc)
4002 return rc;
4003
4004 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4005 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004006 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4007 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004008 name_len++; /* trailing null */
4009 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004010 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004011 name_len = strnlen(searchName, PATH_MAX);
4012 name_len++; /* trailing null */
4013 strncpy(pSMB->FileName, searchName, name_len);
4014 }
4015
Steve French50c2f752007-07-13 00:33:32 +00004016 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004017 pSMB->TotalDataCount = 0;
4018 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004019 /* BB find exact max SMB PDU from sess structure BB */
4020 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004021 pSMB->MaxSetupCount = 0;
4022 pSMB->Reserved = 0;
4023 pSMB->Flags = 0;
4024 pSMB->Timeout = 0;
4025 pSMB->Reserved2 = 0;
4026 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004027 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004028 pSMB->DataCount = 0;
4029 pSMB->DataOffset = 0;
4030 pSMB->SetupCount = 1;
4031 pSMB->Reserved3 = 0;
4032 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4033 byte_count = params + 1 /* pad */ ;
4034 pSMB->TotalParameterCount = cpu_to_le16(params);
4035 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00004036 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004037 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
4038 else
4039 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004040 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004041 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004042 pSMB->ByteCount = cpu_to_le16(byte_count);
4043
4044 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4045 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4046 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004047 cFYI(1, "Send error in QPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004048 } else { /* decode response */
4049 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4050
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004051 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4052 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004053 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004054 rc = -EIO; /* bad smb */
Jeff Layton820a8032011-05-04 08:05:26 -04004055 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
Steve French50c2f752007-07-13 00:33:32 +00004056 rc = -EIO; /* 24 or 26 expected but we do not read
4057 last field */
4058 else if (pFindData) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004059 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004060 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00004061
4062 /* On legacy responses we do not read the last field,
4063 EAsize, fortunately since it varies by subdialect and
4064 also note it differs on Set vs. Get, ie two bytes or 4
4065 bytes depending but we don't care here */
4066 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004067 size = sizeof(FILE_INFO_STANDARD);
4068 else
4069 size = sizeof(FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004070 memcpy((char *) pFindData,
4071 (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004072 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004073 } else
4074 rc = -ENOMEM;
4075 }
4076 cifs_buf_release(pSMB);
4077 if (rc == -EAGAIN)
4078 goto QPathInfoRetry;
4079
4080 return rc;
4081}
4082
4083int
Steve French96daf2b2011-05-27 04:34:02 +00004084CIFSSMBUnixQFileInfo(const int xid, struct cifs_tcon *tcon,
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004085 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
4086{
4087 struct smb_t2_qfi_req *pSMB = NULL;
4088 struct smb_t2_qfi_rsp *pSMBr = NULL;
4089 int rc = 0;
4090 int bytes_returned;
4091 __u16 params, byte_count;
4092
4093UnixQFileInfoRetry:
4094 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4095 (void **) &pSMBr);
4096 if (rc)
4097 return rc;
4098
4099 params = 2 /* level */ + 2 /* fid */;
4100 pSMB->t2.TotalDataCount = 0;
4101 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4102 /* BB find exact max data count below from sess structure BB */
4103 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4104 pSMB->t2.MaxSetupCount = 0;
4105 pSMB->t2.Reserved = 0;
4106 pSMB->t2.Flags = 0;
4107 pSMB->t2.Timeout = 0;
4108 pSMB->t2.Reserved2 = 0;
4109 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4110 Fid) - 4);
4111 pSMB->t2.DataCount = 0;
4112 pSMB->t2.DataOffset = 0;
4113 pSMB->t2.SetupCount = 1;
4114 pSMB->t2.Reserved3 = 0;
4115 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4116 byte_count = params + 1 /* pad */ ;
4117 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4118 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4119 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4120 pSMB->Pad = 0;
4121 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004122 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004123
4124 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4125 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4126 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00004127 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004128 } else { /* decode response */
4129 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4130
Jeff Layton820a8032011-05-04 08:05:26 -04004131 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Steve Frenchf19159d2010-04-21 04:12:10 +00004132 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response.\n"
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004133 "Unix Extensions can be disabled on mount "
Steve Frenchf19159d2010-04-21 04:12:10 +00004134 "by specifying the nosfu mount option.");
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004135 rc = -EIO; /* bad smb */
4136 } else {
4137 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4138 memcpy((char *) pFindData,
4139 (char *) &pSMBr->hdr.Protocol +
4140 data_offset,
4141 sizeof(FILE_UNIX_BASIC_INFO));
4142 }
4143 }
4144
4145 cifs_buf_release(pSMB);
4146 if (rc == -EAGAIN)
4147 goto UnixQFileInfoRetry;
4148
4149 return rc;
4150}
4151
4152int
Steve French96daf2b2011-05-27 04:34:02 +00004153CIFSSMBUnixQPathInfo(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004154 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00004155 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07004156 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004157{
4158/* SMB_QUERY_FILE_UNIX_BASIC */
4159 TRANSACTION2_QPI_REQ *pSMB = NULL;
4160 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4161 int rc = 0;
4162 int bytes_returned = 0;
4163 int name_len;
4164 __u16 params, byte_count;
4165
Joe Perchesb6b38f72010-04-21 03:50:45 +00004166 cFYI(1, "In QPathInfo (Unix) the path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004167UnixQPathInfoRetry:
4168 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4169 (void **) &pSMBr);
4170 if (rc)
4171 return rc;
4172
4173 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4174 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004175 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4176 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004177 name_len++; /* trailing null */
4178 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004179 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004180 name_len = strnlen(searchName, PATH_MAX);
4181 name_len++; /* trailing null */
4182 strncpy(pSMB->FileName, searchName, name_len);
4183 }
4184
Steve French50c2f752007-07-13 00:33:32 +00004185 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004186 pSMB->TotalDataCount = 0;
4187 pSMB->MaxParameterCount = cpu_to_le16(2);
4188 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00004189 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004190 pSMB->MaxSetupCount = 0;
4191 pSMB->Reserved = 0;
4192 pSMB->Flags = 0;
4193 pSMB->Timeout = 0;
4194 pSMB->Reserved2 = 0;
4195 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004196 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004197 pSMB->DataCount = 0;
4198 pSMB->DataOffset = 0;
4199 pSMB->SetupCount = 1;
4200 pSMB->Reserved3 = 0;
4201 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4202 byte_count = params + 1 /* pad */ ;
4203 pSMB->TotalParameterCount = cpu_to_le16(params);
4204 pSMB->ParameterCount = pSMB->TotalParameterCount;
4205 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4206 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004207 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004208 pSMB->ByteCount = cpu_to_le16(byte_count);
4209
4210 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4211 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4212 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004213 cFYI(1, "Send error in QPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004214 } else { /* decode response */
4215 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4216
Jeff Layton820a8032011-05-04 08:05:26 -04004217 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004218 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response.\n"
Steve French1e71f252007-09-20 15:30:07 +00004219 "Unix Extensions can be disabled on mount "
Joe Perchesb6b38f72010-04-21 03:50:45 +00004220 "by specifying the nosfu mount option.");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004221 rc = -EIO; /* bad smb */
4222 } else {
4223 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4224 memcpy((char *) pFindData,
4225 (char *) &pSMBr->hdr.Protocol +
4226 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00004227 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004228 }
4229 }
4230 cifs_buf_release(pSMB);
4231 if (rc == -EAGAIN)
4232 goto UnixQPathInfoRetry;
4233
4234 return rc;
4235}
4236
Linus Torvalds1da177e2005-04-16 15:20:36 -07004237/* xid, tcon, searchName and codepage are input parms, rest are returned */
4238int
Steve French96daf2b2011-05-27 04:34:02 +00004239CIFSFindFirst(const int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004240 const char *searchName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004241 const struct nls_table *nls_codepage,
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004242 __u16 *pnetfid, __u16 search_flags,
Steve French50c2f752007-07-13 00:33:32 +00004243 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004244{
4245/* level 257 SMB_ */
4246 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
4247 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004248 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004249 int rc = 0;
4250 int bytes_returned = 0;
4251 int name_len;
4252 __u16 params, byte_count;
4253
Joe Perchesb6b38f72010-04-21 03:50:45 +00004254 cFYI(1, "In FindFirst for %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004255
4256findFirstRetry:
4257 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4258 (void **) &pSMBr);
4259 if (rc)
4260 return rc;
4261
4262 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4263 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004264 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4265 PATH_MAX, nls_codepage, remap);
Steve French737b7582005-04-28 22:41:06 -07004266 /* We can not add the asterik earlier in case
4267 it got remapped to 0xF03A as if it were part of the
4268 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004269 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07004270 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07004271 pSMB->FileName[name_len+1] = 0;
4272 pSMB->FileName[name_len+2] = '*';
4273 pSMB->FileName[name_len+3] = 0;
4274 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004275 pSMB->FileName[name_len] = 0; /* null terminate just in case */
4276 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07004277 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004278 } else { /* BB add check for overrun of SMB buf BB */
4279 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004280/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00004281 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004282 free buffer exit; BB */
4283 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07004284 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07004285 pSMB->FileName[name_len+1] = '*';
4286 pSMB->FileName[name_len+2] = 0;
4287 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004288 }
4289
4290 params = 12 + name_len /* includes null */ ;
4291 pSMB->TotalDataCount = 0; /* no EAs */
4292 pSMB->MaxParameterCount = cpu_to_le16(10);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004293 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004294 pSMB->MaxSetupCount = 0;
4295 pSMB->Reserved = 0;
4296 pSMB->Flags = 0;
4297 pSMB->Timeout = 0;
4298 pSMB->Reserved2 = 0;
4299 byte_count = params + 1 /* pad */ ;
4300 pSMB->TotalParameterCount = cpu_to_le16(params);
4301 pSMB->ParameterCount = pSMB->TotalParameterCount;
4302 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00004303 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
4304 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004305 pSMB->DataCount = 0;
4306 pSMB->DataOffset = 0;
4307 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
4308 pSMB->Reserved3 = 0;
4309 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
4310 pSMB->SearchAttributes =
4311 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
4312 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00004313 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004314 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004315 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4316
4317 /* BB what should we set StorageType to? Does it matter? BB */
4318 pSMB->SearchStorageType = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004319 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004320 pSMB->ByteCount = cpu_to_le16(byte_count);
4321
4322 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4323 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07004324 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004325
Steve French88274812006-03-09 22:21:45 +00004326 if (rc) {/* BB add logic to retry regular search if Unix search
4327 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004328 /* BB Add code to handle unsupported level rc */
Joe Perchesb6b38f72010-04-21 03:50:45 +00004329 cFYI(1, "Error in FindFirst = %d", rc);
Steve French1982c342005-08-17 12:38:22 -07004330
Steve French88274812006-03-09 22:21:45 +00004331 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004332
4333 /* BB eventually could optimize out free and realloc of buf */
4334 /* for this case */
4335 if (rc == -EAGAIN)
4336 goto findFirstRetry;
4337 } else { /* decode response */
4338 /* BB remember to free buffer if error BB */
4339 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00004340 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004341 unsigned int lnoff;
4342
Linus Torvalds1da177e2005-04-16 15:20:36 -07004343 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004344 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004345 else
Steve French4b18f2a2008-04-29 00:06:05 +00004346 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004347
4348 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004349 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00004350 psrch_inf->srch_entries_start =
4351 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004352 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004353 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
4354 le16_to_cpu(pSMBr->t2.ParameterOffset));
4355
Steve French790fe572007-07-07 19:25:05 +00004356 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004357 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004358 else
Steve French4b18f2a2008-04-29 00:06:05 +00004359 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004360
Steve French50c2f752007-07-13 00:33:32 +00004361 psrch_inf->entries_in_buffer =
4362 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00004363 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004364 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004365 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004366 if (CIFSMaxBufSize < lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004367 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00004368 psrch_inf->last_entry = NULL;
4369 return rc;
4370 }
4371
Steve French0752f152008-10-07 20:03:33 +00004372 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00004373 lnoff;
4374
Linus Torvalds1da177e2005-04-16 15:20:36 -07004375 *pnetfid = parms->SearchHandle;
4376 } else {
4377 cifs_buf_release(pSMB);
4378 }
4379 }
4380
4381 return rc;
4382}
4383
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004384int CIFSFindNext(const int xid, struct cifs_tcon *tcon, __u16 searchHandle,
4385 __u16 search_flags, struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004386{
4387 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
4388 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004389 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004390 char *response_data;
4391 int rc = 0;
Jeff Layton9438fab2011-08-23 07:21:28 -04004392 int bytes_returned;
4393 unsigned int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004394 __u16 params, byte_count;
4395
Joe Perchesb6b38f72010-04-21 03:50:45 +00004396 cFYI(1, "In FindNext");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004397
Steve French4b18f2a2008-04-29 00:06:05 +00004398 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004399 return -ENOENT;
4400
4401 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4402 (void **) &pSMBr);
4403 if (rc)
4404 return rc;
4405
Steve French50c2f752007-07-13 00:33:32 +00004406 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004407 byte_count = 0;
4408 pSMB->TotalDataCount = 0; /* no EAs */
4409 pSMB->MaxParameterCount = cpu_to_le16(8);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004410 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004411 pSMB->MaxSetupCount = 0;
4412 pSMB->Reserved = 0;
4413 pSMB->Flags = 0;
4414 pSMB->Timeout = 0;
4415 pSMB->Reserved2 = 0;
4416 pSMB->ParameterOffset = cpu_to_le16(
4417 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
4418 pSMB->DataCount = 0;
4419 pSMB->DataOffset = 0;
4420 pSMB->SetupCount = 1;
4421 pSMB->Reserved3 = 0;
4422 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
4423 pSMB->SearchHandle = searchHandle; /* always kept as le */
4424 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00004425 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004426 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4427 pSMB->ResumeKey = psrch_inf->resume_key;
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004428 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004429
4430 name_len = psrch_inf->resume_name_len;
4431 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00004432 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004433 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
4434 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07004435 /* 14 byte parm len above enough for 2 byte null terminator */
4436 pSMB->ResumeFileName[name_len] = 0;
4437 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004438 } else {
4439 rc = -EINVAL;
4440 goto FNext2_err_exit;
4441 }
4442 byte_count = params + 1 /* pad */ ;
4443 pSMB->TotalParameterCount = cpu_to_le16(params);
4444 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004445 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004446 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004447
Linus Torvalds1da177e2005-04-16 15:20:36 -07004448 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4449 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07004450 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004451 if (rc) {
4452 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00004453 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07004454 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00004455 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004456 } else
Joe Perchesb6b38f72010-04-21 03:50:45 +00004457 cFYI(1, "FindNext returned = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004458 } else { /* decode response */
4459 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00004460
Steve French790fe572007-07-07 19:25:05 +00004461 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004462 unsigned int lnoff;
4463
Linus Torvalds1da177e2005-04-16 15:20:36 -07004464 /* BB fixme add lock for file (srch_info) struct here */
4465 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004466 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004467 else
Steve French4b18f2a2008-04-29 00:06:05 +00004468 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004469 response_data = (char *) &pSMBr->hdr.Protocol +
4470 le16_to_cpu(pSMBr->t2.ParameterOffset);
4471 parms = (T2_FNEXT_RSP_PARMS *)response_data;
4472 response_data = (char *)&pSMBr->hdr.Protocol +
4473 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00004474 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00004475 cifs_small_buf_release(
4476 psrch_inf->ntwrk_buf_start);
4477 else
4478 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004479 psrch_inf->srch_entries_start = response_data;
4480 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004481 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00004482 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004483 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004484 else
Steve French4b18f2a2008-04-29 00:06:05 +00004485 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00004486 psrch_inf->entries_in_buffer =
4487 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004488 psrch_inf->index_of_last_entry +=
4489 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004490 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004491 if (CIFSMaxBufSize < lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004492 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00004493 psrch_inf->last_entry = NULL;
4494 return rc;
4495 } else
4496 psrch_inf->last_entry =
4497 psrch_inf->srch_entries_start + lnoff;
4498
Joe Perchesb6b38f72010-04-21 03:50:45 +00004499/* cFYI(1, "fnxt2 entries in buf %d index_of_last %d",
4500 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004501
4502 /* BB fixme add unlock here */
4503 }
4504
4505 }
4506
4507 /* BB On error, should we leave previous search buf (and count and
4508 last entry fields) intact or free the previous one? */
4509
4510 /* Note: On -EAGAIN error only caller can retry on handle based calls
4511 since file handle passed in no longer valid */
4512FNext2_err_exit:
4513 if (rc != 0)
4514 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004515 return rc;
4516}
4517
4518int
Steve French96daf2b2011-05-27 04:34:02 +00004519CIFSFindClose(const int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004520 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004521{
4522 int rc = 0;
4523 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004524
Joe Perchesb6b38f72010-04-21 03:50:45 +00004525 cFYI(1, "In CIFSSMBFindClose");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004526 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
4527
4528 /* no sense returning error if session restarted
4529 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00004530 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004531 return 0;
4532 if (rc)
4533 return rc;
4534
Linus Torvalds1da177e2005-04-16 15:20:36 -07004535 pSMB->FileID = searchHandle;
4536 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04004537 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004538 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00004539 cERROR(1, "Send error in FindClose = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00004540
Steve Frencha4544342005-08-24 13:59:35 -07004541 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004542
4543 /* Since session is dead, search handle closed on server already */
4544 if (rc == -EAGAIN)
4545 rc = 0;
4546
4547 return rc;
4548}
4549
Linus Torvalds1da177e2005-04-16 15:20:36 -07004550int
Steve French96daf2b2011-05-27 04:34:02 +00004551CIFSGetSrvInodeNumber(const int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004552 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00004553 __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00004554 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004555{
4556 int rc = 0;
4557 TRANSACTION2_QPI_REQ *pSMB = NULL;
4558 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4559 int name_len, bytes_returned;
4560 __u16 params, byte_count;
4561
Joe Perchesb6b38f72010-04-21 03:50:45 +00004562 cFYI(1, "In GetSrvInodeNum for %s", searchName);
Steve French790fe572007-07-07 19:25:05 +00004563 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00004564 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004565
4566GetInodeNumberRetry:
4567 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004568 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004569 if (rc)
4570 return rc;
4571
Linus Torvalds1da177e2005-04-16 15:20:36 -07004572 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4573 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004574 cifsConvertToUTF16((__le16 *) pSMB->FileName,
4575 searchName, PATH_MAX, nls_codepage,
4576 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004577 name_len++; /* trailing null */
4578 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004579 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004580 name_len = strnlen(searchName, PATH_MAX);
4581 name_len++; /* trailing null */
4582 strncpy(pSMB->FileName, searchName, name_len);
4583 }
4584
4585 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4586 pSMB->TotalDataCount = 0;
4587 pSMB->MaxParameterCount = cpu_to_le16(2);
4588 /* BB find exact max data count below from sess structure BB */
4589 pSMB->MaxDataCount = cpu_to_le16(4000);
4590 pSMB->MaxSetupCount = 0;
4591 pSMB->Reserved = 0;
4592 pSMB->Flags = 0;
4593 pSMB->Timeout = 0;
4594 pSMB->Reserved2 = 0;
4595 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004596 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004597 pSMB->DataCount = 0;
4598 pSMB->DataOffset = 0;
4599 pSMB->SetupCount = 1;
4600 pSMB->Reserved3 = 0;
4601 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4602 byte_count = params + 1 /* pad */ ;
4603 pSMB->TotalParameterCount = cpu_to_le16(params);
4604 pSMB->ParameterCount = pSMB->TotalParameterCount;
4605 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4606 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004607 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004608 pSMB->ByteCount = cpu_to_le16(byte_count);
4609
4610 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4611 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4612 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004613 cFYI(1, "error %d in QueryInternalInfo", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004614 } else {
4615 /* decode response */
4616 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004617 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04004618 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004619 /* If rc should we check for EOPNOSUPP and
4620 disable the srvino flag? or in caller? */
4621 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00004622 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004623 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4624 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00004625 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004626 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00004627 if (count < 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004628 cFYI(1, "Illegal size ret in QryIntrnlInf");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004629 rc = -EIO;
4630 goto GetInodeNumOut;
4631 }
4632 pfinfo = (struct file_internal_info *)
4633 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00004634 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004635 }
4636 }
4637GetInodeNumOut:
4638 cifs_buf_release(pSMB);
4639 if (rc == -EAGAIN)
4640 goto GetInodeNumberRetry;
4641 return rc;
4642}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004643
Igor Mammedovfec45852008-05-16 13:06:30 +04004644/* parses DFS refferal V3 structure
4645 * caller is responsible for freeing target_nodes
4646 * returns:
4647 * on success - 0
4648 * on failure - errno
4649 */
4650static int
Steve Frencha1fe78f2008-05-16 18:48:38 +00004651parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
Igor Mammedovfec45852008-05-16 13:06:30 +04004652 unsigned int *num_of_nodes,
4653 struct dfs_info3_param **target_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004654 const struct nls_table *nls_codepage, int remap,
4655 const char *searchName)
Igor Mammedovfec45852008-05-16 13:06:30 +04004656{
4657 int i, rc = 0;
4658 char *data_end;
4659 bool is_unicode;
4660 struct dfs_referral_level_3 *ref;
4661
Harvey Harrison5ca33c62008-07-23 17:45:58 -07004662 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4663 is_unicode = true;
4664 else
4665 is_unicode = false;
Igor Mammedovfec45852008-05-16 13:06:30 +04004666 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
4667
4668 if (*num_of_nodes < 1) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004669 cERROR(1, "num_referrals: must be at least > 0,"
4670 "but we get num_referrals = %d\n", *num_of_nodes);
Igor Mammedovfec45852008-05-16 13:06:30 +04004671 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004672 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004673 }
4674
4675 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
Al Viro1d92cfd2008-06-02 10:59:02 +01004676 if (ref->VersionNumber != cpu_to_le16(3)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004677 cERROR(1, "Referrals of V%d version are not supported,"
4678 "should be V3", le16_to_cpu(ref->VersionNumber));
Igor Mammedovfec45852008-05-16 13:06:30 +04004679 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004680 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004681 }
4682
4683 /* get the upper boundary of the resp buffer */
4684 data_end = (char *)(&(pSMBr->PathConsumed)) +
4685 le16_to_cpu(pSMBr->t2.DataCount);
4686
Steve Frenchf19159d2010-04-21 04:12:10 +00004687 cFYI(1, "num_referrals: %d dfs flags: 0x%x ...\n",
Igor Mammedovfec45852008-05-16 13:06:30 +04004688 *num_of_nodes,
Joe Perchesb6b38f72010-04-21 03:50:45 +00004689 le32_to_cpu(pSMBr->DFSFlags));
Igor Mammedovfec45852008-05-16 13:06:30 +04004690
4691 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
4692 *num_of_nodes, GFP_KERNEL);
4693 if (*target_nodes == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004694 cERROR(1, "Failed to allocate buffer for target_nodes\n");
Igor Mammedovfec45852008-05-16 13:06:30 +04004695 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004696 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004697 }
4698
Daniel Mack3ad2f3f2010-02-03 08:01:28 +08004699 /* collect necessary data from referrals */
Igor Mammedovfec45852008-05-16 13:06:30 +04004700 for (i = 0; i < *num_of_nodes; i++) {
4701 char *temp;
4702 int max_len;
4703 struct dfs_info3_param *node = (*target_nodes)+i;
4704
Steve French0e0d2cf2009-05-01 05:27:32 +00004705 node->flags = le32_to_cpu(pSMBr->DFSFlags);
Igor Mammedov2c556082008-10-23 13:58:42 +04004706 if (is_unicode) {
Jeff Layton331c3132008-12-17 06:31:53 -05004707 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4708 GFP_KERNEL);
Steve French2920ee22009-08-31 15:27:26 +00004709 if (tmp == NULL) {
4710 rc = -ENOMEM;
4711 goto parse_DFS_referrals_exit;
4712 }
Steve Frenchacbbb762012-01-18 22:32:33 -06004713 cifsConvertToUTF16((__le16 *) tmp, searchName,
4714 PATH_MAX, nls_codepage, remap);
4715 node->path_consumed = cifs_utf16_bytes(tmp,
Jeff Layton69f801f2009-04-30 06:46:32 -04004716 le16_to_cpu(pSMBr->PathConsumed),
Igor Mammedov2c556082008-10-23 13:58:42 +04004717 nls_codepage);
4718 kfree(tmp);
4719 } else
4720 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4721
Igor Mammedovfec45852008-05-16 13:06:30 +04004722 node->server_type = le16_to_cpu(ref->ServerType);
4723 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4724
4725 /* copy DfsPath */
4726 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4727 max_len = data_end - temp;
Steve Frenchacbbb762012-01-18 22:32:33 -06004728 node->path_name = cifs_strndup_from_utf16(temp, max_len,
4729 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004730 if (!node->path_name) {
4731 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004732 goto parse_DFS_referrals_exit;
Jeff Layton066ce682009-04-30 07:16:14 -04004733 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004734
4735 /* copy link target UNC */
4736 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4737 max_len = data_end - temp;
Steve Frenchacbbb762012-01-18 22:32:33 -06004738 node->node_name = cifs_strndup_from_utf16(temp, max_len,
4739 is_unicode, nls_codepage);
Stefan Metzmacherd8f27992012-05-04 00:19:28 +02004740 if (!node->node_name) {
Jeff Laytond8e2f532009-05-14 07:46:59 -04004741 rc = -ENOMEM;
Stefan Metzmacherd8f27992012-05-04 00:19:28 +02004742 goto parse_DFS_referrals_exit;
4743 }
4744
4745 ref++;
Igor Mammedovfec45852008-05-16 13:06:30 +04004746 }
4747
Steve Frencha1fe78f2008-05-16 18:48:38 +00004748parse_DFS_referrals_exit:
Igor Mammedovfec45852008-05-16 13:06:30 +04004749 if (rc) {
4750 free_dfs_info_array(*target_nodes, *num_of_nodes);
4751 *target_nodes = NULL;
4752 *num_of_nodes = 0;
4753 }
4754 return rc;
4755}
4756
Linus Torvalds1da177e2005-04-16 15:20:36 -07004757int
Steve French96daf2b2011-05-27 04:34:02 +00004758CIFSGetDFSRefer(const int xid, struct cifs_ses *ses,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004759 const unsigned char *searchName,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004760 struct dfs_info3_param **target_nodes,
4761 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004762 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004763{
4764/* TRANS2_GET_DFS_REFERRAL */
4765 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4766 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004767 int rc = 0;
4768 int bytes_returned;
4769 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004770 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004771 *num_of_nodes = 0;
4772 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004773
Joe Perchesb6b38f72010-04-21 03:50:45 +00004774 cFYI(1, "In GetDFSRefer the path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004775 if (ses == NULL)
4776 return -ENODEV;
4777getDFSRetry:
4778 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4779 (void **) &pSMBr);
4780 if (rc)
4781 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004782
4783 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004784 but should never be null here anyway */
4785 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004786 pSMB->hdr.Tid = ses->ipc_tid;
4787 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004788 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004789 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004790 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004791 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004792
4793 if (ses->capabilities & CAP_UNICODE) {
4794 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4795 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004796 cifsConvertToUTF16((__le16 *) pSMB->RequestFileName,
4797 searchName, PATH_MAX, nls_codepage,
4798 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004799 name_len++; /* trailing null */
4800 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004801 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004802 name_len = strnlen(searchName, PATH_MAX);
4803 name_len++; /* trailing null */
4804 strncpy(pSMB->RequestFileName, searchName, name_len);
4805 }
4806
Steve French790fe572007-07-07 19:25:05 +00004807 if (ses->server) {
Steve French96daf2b2011-05-27 04:34:02 +00004808 if (ses->server->sec_mode &
Steve French1a4e15a2006-10-12 21:33:51 +00004809 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4810 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4811 }
4812
Steve French50c2f752007-07-13 00:33:32 +00004813 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004814
Linus Torvalds1da177e2005-04-16 15:20:36 -07004815 params = 2 /* level */ + name_len /*includes null */ ;
4816 pSMB->TotalDataCount = 0;
4817 pSMB->DataCount = 0;
4818 pSMB->DataOffset = 0;
4819 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004820 /* BB find exact max SMB PDU from sess structure BB */
4821 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004822 pSMB->MaxSetupCount = 0;
4823 pSMB->Reserved = 0;
4824 pSMB->Flags = 0;
4825 pSMB->Timeout = 0;
4826 pSMB->Reserved2 = 0;
4827 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004828 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004829 pSMB->SetupCount = 1;
4830 pSMB->Reserved3 = 0;
4831 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4832 byte_count = params + 3 /* pad */ ;
4833 pSMB->ParameterCount = cpu_to_le16(params);
4834 pSMB->TotalParameterCount = pSMB->ParameterCount;
4835 pSMB->MaxReferralLevel = cpu_to_le16(3);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004836 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004837 pSMB->ByteCount = cpu_to_le16(byte_count);
4838
4839 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4840 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4841 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004842 cFYI(1, "Send error in GetDFSRefer = %d", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004843 goto GetDFSRefExit;
4844 }
4845 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004846
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004847 /* BB Also check if enough total bytes returned? */
Jeff Layton820a8032011-05-04 08:05:26 -04004848 if (rc || get_bcc(&pSMBr->hdr) < 17) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004849 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004850 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004851 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004852
Joe Perchesb6b38f72010-04-21 03:50:45 +00004853 cFYI(1, "Decoding GetDFSRefer response BCC: %d Offset %d",
Jeff Layton820a8032011-05-04 08:05:26 -04004854 get_bcc(&pSMBr->hdr),
Joe Perchesb6b38f72010-04-21 03:50:45 +00004855 le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04004856
4857 /* parse returned result into more usable form */
Steve Frencha1fe78f2008-05-16 18:48:38 +00004858 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004859 target_nodes, nls_codepage, remap,
4860 searchName);
Igor Mammedovfec45852008-05-16 13:06:30 +04004861
Linus Torvalds1da177e2005-04-16 15:20:36 -07004862GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004863 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004864
4865 if (rc == -EAGAIN)
4866 goto getDFSRetry;
4867
4868 return rc;
4869}
4870
Steve French20962432005-09-21 22:05:57 -07004871/* Query File System Info such as free space to old servers such as Win 9x */
4872int
Steve French96daf2b2011-05-27 04:34:02 +00004873SMBOldQFSInfo(const int xid, struct cifs_tcon *tcon, struct kstatfs *FSData)
Steve French20962432005-09-21 22:05:57 -07004874{
4875/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4876 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4877 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4878 FILE_SYSTEM_ALLOC_INFO *response_data;
4879 int rc = 0;
4880 int bytes_returned = 0;
4881 __u16 params, byte_count;
4882
Joe Perchesb6b38f72010-04-21 03:50:45 +00004883 cFYI(1, "OldQFSInfo");
Steve French20962432005-09-21 22:05:57 -07004884oldQFSInfoRetry:
4885 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4886 (void **) &pSMBr);
4887 if (rc)
4888 return rc;
Steve French20962432005-09-21 22:05:57 -07004889
4890 params = 2; /* level */
4891 pSMB->TotalDataCount = 0;
4892 pSMB->MaxParameterCount = cpu_to_le16(2);
4893 pSMB->MaxDataCount = cpu_to_le16(1000);
4894 pSMB->MaxSetupCount = 0;
4895 pSMB->Reserved = 0;
4896 pSMB->Flags = 0;
4897 pSMB->Timeout = 0;
4898 pSMB->Reserved2 = 0;
4899 byte_count = params + 1 /* pad */ ;
4900 pSMB->TotalParameterCount = cpu_to_le16(params);
4901 pSMB->ParameterCount = pSMB->TotalParameterCount;
4902 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4903 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4904 pSMB->DataCount = 0;
4905 pSMB->DataOffset = 0;
4906 pSMB->SetupCount = 1;
4907 pSMB->Reserved3 = 0;
4908 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4909 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004910 inc_rfc1001_len(pSMB, byte_count);
Steve French20962432005-09-21 22:05:57 -07004911 pSMB->ByteCount = cpu_to_le16(byte_count);
4912
4913 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4914 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4915 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004916 cFYI(1, "Send error in QFSInfo = %d", rc);
Steve French20962432005-09-21 22:05:57 -07004917 } else { /* decode response */
4918 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4919
Jeff Layton820a8032011-05-04 08:05:26 -04004920 if (rc || get_bcc(&pSMBr->hdr) < 18)
Steve French20962432005-09-21 22:05:57 -07004921 rc = -EIO; /* bad smb */
4922 else {
4923 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004924 cFYI(1, "qfsinf resp BCC: %d Offset %d",
Jeff Layton820a8032011-05-04 08:05:26 -04004925 get_bcc(&pSMBr->hdr), data_offset);
Steve French20962432005-09-21 22:05:57 -07004926
Steve French50c2f752007-07-13 00:33:32 +00004927 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004928 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4929 FSData->f_bsize =
4930 le16_to_cpu(response_data->BytesPerSector) *
4931 le32_to_cpu(response_data->
4932 SectorsPerAllocationUnit);
4933 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004934 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004935 FSData->f_bfree = FSData->f_bavail =
4936 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004937 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
4938 (unsigned long long)FSData->f_blocks,
4939 (unsigned long long)FSData->f_bfree,
4940 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07004941 }
4942 }
4943 cifs_buf_release(pSMB);
4944
4945 if (rc == -EAGAIN)
4946 goto oldQFSInfoRetry;
4947
4948 return rc;
4949}
4950
Linus Torvalds1da177e2005-04-16 15:20:36 -07004951int
Steve French96daf2b2011-05-27 04:34:02 +00004952CIFSSMBQFSInfo(const int xid, struct cifs_tcon *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004953{
4954/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4955 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4956 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4957 FILE_SYSTEM_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, "In QFSInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004963QFSInfoRetry:
4964 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4965 (void **) &pSMBr);
4966 if (rc)
4967 return rc;
4968
4969 params = 2; /* level */
4970 pSMB->TotalDataCount = 0;
4971 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004972 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004973 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(
Steve French50c2f752007-07-13 00:33:32 +00004982 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004983 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_QUERY_FS_SIZE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004989 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -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);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004996 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00004997 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004998
Jeff Layton820a8032011-05-04 08:05:26 -04004999 if (rc || get_bcc(&pSMBr->hdr) < 24)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005000 rc = -EIO; /* bad smb */
5001 else {
5002 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005003
5004 response_data =
5005 (FILE_SYSTEM_INFO
5006 *) (((char *) &pSMBr->hdr.Protocol) +
5007 data_offset);
5008 FSData->f_bsize =
5009 le32_to_cpu(response_data->BytesPerSector) *
5010 le32_to_cpu(response_data->
5011 SectorsPerAllocationUnit);
5012 FSData->f_blocks =
5013 le64_to_cpu(response_data->TotalAllocationUnits);
5014 FSData->f_bfree = FSData->f_bavail =
5015 le64_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);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005020 }
5021 }
5022 cifs_buf_release(pSMB);
5023
5024 if (rc == -EAGAIN)
5025 goto QFSInfoRetry;
5026
5027 return rc;
5028}
5029
5030int
Steve French96daf2b2011-05-27 04:34:02 +00005031CIFSSMBQFSAttributeInfo(const int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005032{
5033/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
5034 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5035 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5036 FILE_SYSTEM_ATTRIBUTE_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 QFSAttributeInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005042QFSAttributeRetry:
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 French582d21e2008-05-13 04:54:12 +00005051 /* BB find exact max SMB PDU from sess structure BB */
5052 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005053 pSMB->MaxSetupCount = 0;
5054 pSMB->Reserved = 0;
5055 pSMB->Flags = 0;
5056 pSMB->Timeout = 0;
5057 pSMB->Reserved2 = 0;
5058 byte_count = params + 1 /* pad */ ;
5059 pSMB->TotalParameterCount = cpu_to_le16(params);
5060 pSMB->ParameterCount = pSMB->TotalParameterCount;
5061 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005062 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005063 pSMB->DataCount = 0;
5064 pSMB->DataOffset = 0;
5065 pSMB->SetupCount = 1;
5066 pSMB->Reserved3 = 0;
5067 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5068 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005069 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005070 pSMB->ByteCount = cpu_to_le16(byte_count);
5071
5072 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5073 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5074 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005075 cERROR(1, "Send error in QFSAttributeInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005076 } else { /* decode response */
5077 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5078
Jeff Layton820a8032011-05-04 08:05:26 -04005079 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Steve French50c2f752007-07-13 00:33:32 +00005080 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005081 rc = -EIO; /* bad smb */
5082 } else {
5083 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5084 response_data =
5085 (FILE_SYSTEM_ATTRIBUTE_INFO
5086 *) (((char *) &pSMBr->hdr.Protocol) +
5087 data_offset);
5088 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005089 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005090 }
5091 }
5092 cifs_buf_release(pSMB);
5093
5094 if (rc == -EAGAIN)
5095 goto QFSAttributeRetry;
5096
5097 return rc;
5098}
5099
5100int
Steve French96daf2b2011-05-27 04:34:02 +00005101CIFSSMBQFSDeviceInfo(const int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005102{
5103/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
5104 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5105 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5106 FILE_SYSTEM_DEVICE_INFO *response_data;
5107 int rc = 0;
5108 int bytes_returned = 0;
5109 __u16 params, byte_count;
5110
Joe Perchesb6b38f72010-04-21 03:50:45 +00005111 cFYI(1, "In QFSDeviceInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005112QFSDeviceRetry:
5113 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5114 (void **) &pSMBr);
5115 if (rc)
5116 return rc;
5117
5118 params = 2; /* level */
5119 pSMB->TotalDataCount = 0;
5120 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005121 /* BB find exact max SMB PDU from sess structure BB */
5122 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005123 pSMB->MaxSetupCount = 0;
5124 pSMB->Reserved = 0;
5125 pSMB->Flags = 0;
5126 pSMB->Timeout = 0;
5127 pSMB->Reserved2 = 0;
5128 byte_count = params + 1 /* pad */ ;
5129 pSMB->TotalParameterCount = cpu_to_le16(params);
5130 pSMB->ParameterCount = pSMB->TotalParameterCount;
5131 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005132 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005133
5134 pSMB->DataCount = 0;
5135 pSMB->DataOffset = 0;
5136 pSMB->SetupCount = 1;
5137 pSMB->Reserved3 = 0;
5138 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5139 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005140 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005141 pSMB->ByteCount = cpu_to_le16(byte_count);
5142
5143 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5144 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5145 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005146 cFYI(1, "Send error in QFSDeviceInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005147 } else { /* decode response */
5148 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5149
Jeff Layton820a8032011-05-04 08:05:26 -04005150 if (rc || get_bcc(&pSMBr->hdr) <
5151 sizeof(FILE_SYSTEM_DEVICE_INFO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005152 rc = -EIO; /* bad smb */
5153 else {
5154 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5155 response_data =
Steve French737b7582005-04-28 22:41:06 -07005156 (FILE_SYSTEM_DEVICE_INFO *)
5157 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07005158 data_offset);
5159 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005160 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005161 }
5162 }
5163 cifs_buf_release(pSMB);
5164
5165 if (rc == -EAGAIN)
5166 goto QFSDeviceRetry;
5167
5168 return rc;
5169}
5170
5171int
Steve French96daf2b2011-05-27 04:34:02 +00005172CIFSSMBQFSUnixInfo(const int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005173{
5174/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
5175 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5176 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5177 FILE_SYSTEM_UNIX_INFO *response_data;
5178 int rc = 0;
5179 int bytes_returned = 0;
5180 __u16 params, byte_count;
5181
Joe Perchesb6b38f72010-04-21 03:50:45 +00005182 cFYI(1, "In QFSUnixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005183QFSUnixRetry:
Jeff Laytonf5695992010-09-29 15:27:08 -04005184 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5185 (void **) &pSMB, (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005186 if (rc)
5187 return rc;
5188
5189 params = 2; /* level */
5190 pSMB->TotalDataCount = 0;
5191 pSMB->DataCount = 0;
5192 pSMB->DataOffset = 0;
5193 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005194 /* BB find exact max SMB PDU from sess structure BB */
5195 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005196 pSMB->MaxSetupCount = 0;
5197 pSMB->Reserved = 0;
5198 pSMB->Flags = 0;
5199 pSMB->Timeout = 0;
5200 pSMB->Reserved2 = 0;
5201 byte_count = params + 1 /* pad */ ;
5202 pSMB->ParameterCount = cpu_to_le16(params);
5203 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005204 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5205 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005206 pSMB->SetupCount = 1;
5207 pSMB->Reserved3 = 0;
5208 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5209 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005210 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005211 pSMB->ByteCount = cpu_to_le16(byte_count);
5212
5213 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5214 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5215 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005216 cERROR(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005217 } else { /* decode response */
5218 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5219
Jeff Layton820a8032011-05-04 08:05:26 -04005220 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005221 rc = -EIO; /* bad smb */
5222 } else {
5223 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5224 response_data =
5225 (FILE_SYSTEM_UNIX_INFO
5226 *) (((char *) &pSMBr->hdr.Protocol) +
5227 data_offset);
5228 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005229 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005230 }
5231 }
5232 cifs_buf_release(pSMB);
5233
5234 if (rc == -EAGAIN)
5235 goto QFSUnixRetry;
5236
5237
5238 return rc;
5239}
5240
Jeremy Allisonac670552005-06-22 17:26:35 -07005241int
Steve French96daf2b2011-05-27 04:34:02 +00005242CIFSSMBSetFSUnixInfo(const int xid, struct cifs_tcon *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07005243{
5244/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
5245 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
5246 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
5247 int rc = 0;
5248 int bytes_returned = 0;
5249 __u16 params, param_offset, offset, byte_count;
5250
Joe Perchesb6b38f72010-04-21 03:50:45 +00005251 cFYI(1, "In SETFSUnixInfo");
Jeremy Allisonac670552005-06-22 17:26:35 -07005252SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00005253 /* BB switch to small buf init to save memory */
Jeff Laytonf5695992010-09-29 15:27:08 -04005254 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5255 (void **) &pSMB, (void **) &pSMBr);
Jeremy Allisonac670552005-06-22 17:26:35 -07005256 if (rc)
5257 return rc;
5258
5259 params = 4; /* 2 bytes zero followed by info level. */
5260 pSMB->MaxSetupCount = 0;
5261 pSMB->Reserved = 0;
5262 pSMB->Flags = 0;
5263 pSMB->Timeout = 0;
5264 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00005265 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
5266 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07005267 offset = param_offset + params;
5268
5269 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00005270 /* BB find exact max SMB PDU from sess structure BB */
5271 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07005272 pSMB->SetupCount = 1;
5273 pSMB->Reserved3 = 0;
5274 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
5275 byte_count = 1 /* pad */ + params + 12;
5276
5277 pSMB->DataCount = cpu_to_le16(12);
5278 pSMB->ParameterCount = cpu_to_le16(params);
5279 pSMB->TotalDataCount = pSMB->DataCount;
5280 pSMB->TotalParameterCount = pSMB->ParameterCount;
5281 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5282 pSMB->DataOffset = cpu_to_le16(offset);
5283
5284 /* Params. */
5285 pSMB->FileNum = 0;
5286 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
5287
5288 /* Data. */
5289 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
5290 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
5291 pSMB->ClientUnixCap = cpu_to_le64(cap);
5292
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005293 inc_rfc1001_len(pSMB, byte_count);
Jeremy Allisonac670552005-06-22 17:26:35 -07005294 pSMB->ByteCount = cpu_to_le16(byte_count);
5295
5296 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5297 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5298 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005299 cERROR(1, "Send error in SETFSUnixInfo = %d", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07005300 } else { /* decode response */
5301 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00005302 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07005303 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07005304 }
5305 cifs_buf_release(pSMB);
5306
5307 if (rc == -EAGAIN)
5308 goto SETFSUnixRetry;
5309
5310 return rc;
5311}
5312
5313
Linus Torvalds1da177e2005-04-16 15:20:36 -07005314
5315int
Steve French96daf2b2011-05-27 04:34:02 +00005316CIFSSMBQFSPosixInfo(const int xid, struct cifs_tcon *tcon,
Steve French737b7582005-04-28 22:41:06 -07005317 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005318{
5319/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
5320 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5321 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5322 FILE_SYSTEM_POSIX_INFO *response_data;
5323 int rc = 0;
5324 int bytes_returned = 0;
5325 __u16 params, byte_count;
5326
Joe Perchesb6b38f72010-04-21 03:50:45 +00005327 cFYI(1, "In QFSPosixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005328QFSPosixRetry:
5329 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5330 (void **) &pSMBr);
5331 if (rc)
5332 return rc;
5333
5334 params = 2; /* level */
5335 pSMB->TotalDataCount = 0;
5336 pSMB->DataCount = 0;
5337 pSMB->DataOffset = 0;
5338 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005339 /* BB find exact max SMB PDU from sess structure BB */
5340 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005341 pSMB->MaxSetupCount = 0;
5342 pSMB->Reserved = 0;
5343 pSMB->Flags = 0;
5344 pSMB->Timeout = 0;
5345 pSMB->Reserved2 = 0;
5346 byte_count = params + 1 /* pad */ ;
5347 pSMB->ParameterCount = cpu_to_le16(params);
5348 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005349 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5350 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005351 pSMB->SetupCount = 1;
5352 pSMB->Reserved3 = 0;
5353 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5354 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005355 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005356 pSMB->ByteCount = cpu_to_le16(byte_count);
5357
5358 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5359 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5360 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005361 cFYI(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005362 } else { /* decode response */
5363 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5364
Jeff Layton820a8032011-05-04 08:05:26 -04005365 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005366 rc = -EIO; /* bad smb */
5367 } else {
5368 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5369 response_data =
5370 (FILE_SYSTEM_POSIX_INFO
5371 *) (((char *) &pSMBr->hdr.Protocol) +
5372 data_offset);
5373 FSData->f_bsize =
5374 le32_to_cpu(response_data->BlockSize);
5375 FSData->f_blocks =
5376 le64_to_cpu(response_data->TotalBlocks);
5377 FSData->f_bfree =
5378 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00005379 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005380 FSData->f_bavail = FSData->f_bfree;
5381 } else {
5382 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00005383 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005384 }
Steve French790fe572007-07-07 19:25:05 +00005385 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005386 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00005387 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00005388 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005389 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00005390 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005391 }
5392 }
5393 cifs_buf_release(pSMB);
5394
5395 if (rc == -EAGAIN)
5396 goto QFSPosixRetry;
5397
5398 return rc;
5399}
5400
5401
Steve French50c2f752007-07-13 00:33:32 +00005402/* We can not use write of zero bytes trick to
5403 set file size due to need for large file support. Also note that
5404 this SetPathInfo is preferred to SetFileInfo based method in next
Linus Torvalds1da177e2005-04-16 15:20:36 -07005405 routine which is only needed to work around a sharing violation bug
5406 in Samba which this routine can run into */
5407
5408int
Steve French96daf2b2011-05-27 04:34:02 +00005409CIFSSMBSetEOF(const int xid, struct cifs_tcon *tcon, const char *fileName,
Steve French4b18f2a2008-04-29 00:06:05 +00005410 __u64 size, bool SetAllocation,
Steve French737b7582005-04-28 22:41:06 -07005411 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005412{
5413 struct smb_com_transaction2_spi_req *pSMB = NULL;
5414 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5415 struct file_end_of_file_info *parm_data;
5416 int name_len;
5417 int rc = 0;
5418 int bytes_returned = 0;
5419 __u16 params, byte_count, data_count, param_offset, offset;
5420
Joe Perchesb6b38f72010-04-21 03:50:45 +00005421 cFYI(1, "In SetEOF");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005422SetEOFRetry:
5423 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5424 (void **) &pSMBr);
5425 if (rc)
5426 return rc;
5427
5428 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5429 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005430 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5431 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005432 name_len++; /* trailing null */
5433 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005434 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005435 name_len = strnlen(fileName, PATH_MAX);
5436 name_len++; /* trailing null */
5437 strncpy(pSMB->FileName, fileName, name_len);
5438 }
5439 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005440 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005441 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07005442 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005443 pSMB->MaxSetupCount = 0;
5444 pSMB->Reserved = 0;
5445 pSMB->Flags = 0;
5446 pSMB->Timeout = 0;
5447 pSMB->Reserved2 = 0;
5448 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005449 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005450 offset = param_offset + params;
Steve French790fe572007-07-07 19:25:05 +00005451 if (SetAllocation) {
Steve French50c2f752007-07-13 00:33:32 +00005452 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5453 pSMB->InformationLevel =
5454 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5455 else
5456 pSMB->InformationLevel =
5457 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5458 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005459 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5460 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005461 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005462 else
5463 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005464 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005465 }
5466
5467 parm_data =
5468 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
5469 offset);
5470 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5471 pSMB->DataOffset = cpu_to_le16(offset);
5472 pSMB->SetupCount = 1;
5473 pSMB->Reserved3 = 0;
5474 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5475 byte_count = 3 /* pad */ + params + data_count;
5476 pSMB->DataCount = cpu_to_le16(data_count);
5477 pSMB->TotalDataCount = pSMB->DataCount;
5478 pSMB->ParameterCount = cpu_to_le16(params);
5479 pSMB->TotalParameterCount = pSMB->ParameterCount;
5480 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005481 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005482 parm_data->FileSize = cpu_to_le64(size);
5483 pSMB->ByteCount = cpu_to_le16(byte_count);
5484 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5485 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005486 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005487 cFYI(1, "SetPathInfo (file size) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005488
5489 cifs_buf_release(pSMB);
5490
5491 if (rc == -EAGAIN)
5492 goto SetEOFRetry;
5493
5494 return rc;
5495}
5496
5497int
Steve French96daf2b2011-05-27 04:34:02 +00005498CIFSSMBSetFileSize(const int xid, struct cifs_tcon *tcon, __u64 size,
Steve French4b18f2a2008-04-29 00:06:05 +00005499 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005500{
5501 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005502 struct file_end_of_file_info *parm_data;
5503 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005504 __u16 params, param_offset, offset, byte_count, count;
5505
Joe Perchesb6b38f72010-04-21 03:50:45 +00005506 cFYI(1, "SetFileSize (via SetFileInfo) %lld",
5507 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07005508 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5509
Linus Torvalds1da177e2005-04-16 15:20:36 -07005510 if (rc)
5511 return rc;
5512
5513 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5514 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005515
Linus Torvalds1da177e2005-04-16 15:20:36 -07005516 params = 6;
5517 pSMB->MaxSetupCount = 0;
5518 pSMB->Reserved = 0;
5519 pSMB->Flags = 0;
5520 pSMB->Timeout = 0;
5521 pSMB->Reserved2 = 0;
5522 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5523 offset = param_offset + params;
5524
Linus Torvalds1da177e2005-04-16 15:20:36 -07005525 count = sizeof(struct file_end_of_file_info);
5526 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005527 /* BB find exact max SMB PDU from sess structure BB */
5528 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005529 pSMB->SetupCount = 1;
5530 pSMB->Reserved3 = 0;
5531 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5532 byte_count = 3 /* pad */ + params + count;
5533 pSMB->DataCount = cpu_to_le16(count);
5534 pSMB->ParameterCount = cpu_to_le16(params);
5535 pSMB->TotalDataCount = pSMB->DataCount;
5536 pSMB->TotalParameterCount = pSMB->ParameterCount;
5537 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5538 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00005539 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
5540 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005541 pSMB->DataOffset = cpu_to_le16(offset);
5542 parm_data->FileSize = cpu_to_le64(size);
5543 pSMB->Fid = fid;
Steve French790fe572007-07-07 19:25:05 +00005544 if (SetAllocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005545 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5546 pSMB->InformationLevel =
5547 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5548 else
5549 pSMB->InformationLevel =
5550 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00005551 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005552 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5553 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005554 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005555 else
5556 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005557 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005558 }
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 pSMB->ByteCount = cpu_to_le16(byte_count);
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005562 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005563 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005564 cFYI(1, "Send error in SetFileInfo (SetFileSize) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005565 }
5566
Steve French50c2f752007-07-13 00:33:32 +00005567 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005568 since file handle passed in no longer valid */
5569
5570 return rc;
5571}
5572
Steve French50c2f752007-07-13 00:33:32 +00005573/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07005574 an open handle, rather than by pathname - this is awkward due to
5575 potential access conflicts on the open, but it is unavoidable for these
5576 old servers since the only other choice is to go from 100 nanosecond DCE
5577 time and resort to the original setpathinfo level which takes the ancient
5578 DOS time format with 2 second granularity */
5579int
Steve French96daf2b2011-05-27 04:34:02 +00005580CIFSSMBSetFileInfo(const int xid, struct cifs_tcon *tcon,
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005581 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005582{
5583 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005584 char *data_offset;
5585 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005586 __u16 params, param_offset, offset, byte_count, count;
5587
Joe Perchesb6b38f72010-04-21 03:50:45 +00005588 cFYI(1, "Set Times (via SetFileInfo)");
Steve Frenchcd634992005-04-28 22:41:10 -07005589 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5590
Linus Torvalds1da177e2005-04-16 15:20:36 -07005591 if (rc)
5592 return rc;
5593
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005594 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5595 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005596
Linus Torvalds1da177e2005-04-16 15:20:36 -07005597 params = 6;
5598 pSMB->MaxSetupCount = 0;
5599 pSMB->Reserved = 0;
5600 pSMB->Flags = 0;
5601 pSMB->Timeout = 0;
5602 pSMB->Reserved2 = 0;
5603 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5604 offset = param_offset + params;
5605
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005606 data_offset = (char *)pSMB +
5607 offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005608
Steve French26f57362007-08-30 22:09:15 +00005609 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005610 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005611 /* BB find max SMB PDU from sess */
5612 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005613 pSMB->SetupCount = 1;
5614 pSMB->Reserved3 = 0;
5615 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5616 byte_count = 3 /* pad */ + params + count;
5617 pSMB->DataCount = cpu_to_le16(count);
5618 pSMB->ParameterCount = cpu_to_le16(params);
5619 pSMB->TotalDataCount = pSMB->DataCount;
5620 pSMB->TotalParameterCount = pSMB->ParameterCount;
5621 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5622 pSMB->DataOffset = cpu_to_le16(offset);
5623 pSMB->Fid = fid;
5624 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5625 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5626 else
5627 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5628 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005629 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005630 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005631 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005632 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005633 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005634 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005635
Steve French50c2f752007-07-13 00:33:32 +00005636 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005637 since file handle passed in no longer valid */
5638
5639 return rc;
5640}
5641
Jeff Layton6d22f092008-09-23 11:48:35 -04005642int
Steve French96daf2b2011-05-27 04:34:02 +00005643CIFSSMBSetFileDisposition(const int xid, struct cifs_tcon *tcon,
Jeff Layton6d22f092008-09-23 11:48:35 -04005644 bool delete_file, __u16 fid, __u32 pid_of_opener)
5645{
5646 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5647 char *data_offset;
5648 int rc = 0;
5649 __u16 params, param_offset, offset, byte_count, count;
5650
Joe Perchesb6b38f72010-04-21 03:50:45 +00005651 cFYI(1, "Set File Disposition (via SetFileInfo)");
Jeff Layton6d22f092008-09-23 11:48:35 -04005652 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5653
5654 if (rc)
5655 return rc;
5656
5657 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5658 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5659
5660 params = 6;
5661 pSMB->MaxSetupCount = 0;
5662 pSMB->Reserved = 0;
5663 pSMB->Flags = 0;
5664 pSMB->Timeout = 0;
5665 pSMB->Reserved2 = 0;
5666 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5667 offset = param_offset + params;
5668
5669 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5670
5671 count = 1;
5672 pSMB->MaxParameterCount = cpu_to_le16(2);
5673 /* BB find max SMB PDU from sess */
5674 pSMB->MaxDataCount = cpu_to_le16(1000);
5675 pSMB->SetupCount = 1;
5676 pSMB->Reserved3 = 0;
5677 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5678 byte_count = 3 /* pad */ + params + count;
5679 pSMB->DataCount = cpu_to_le16(count);
5680 pSMB->ParameterCount = cpu_to_le16(params);
5681 pSMB->TotalDataCount = pSMB->DataCount;
5682 pSMB->TotalParameterCount = pSMB->ParameterCount;
5683 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5684 pSMB->DataOffset = cpu_to_le16(offset);
5685 pSMB->Fid = fid;
5686 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5687 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005688 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton6d22f092008-09-23 11:48:35 -04005689 pSMB->ByteCount = cpu_to_le16(byte_count);
5690 *data_offset = delete_file ? 1 : 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005691 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Jeff Layton6d22f092008-09-23 11:48:35 -04005692 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005693 cFYI(1, "Send error in SetFileDisposition = %d", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005694
5695 return rc;
5696}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005697
5698int
Steve French96daf2b2011-05-27 04:34:02 +00005699CIFSSMBSetPathInfo(const int xid, struct cifs_tcon *tcon,
Jeff Layton6fc000e2008-08-02 07:26:12 -04005700 const char *fileName, const FILE_BASIC_INFO *data,
5701 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005702{
5703 TRANSACTION2_SPI_REQ *pSMB = NULL;
5704 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5705 int name_len;
5706 int rc = 0;
5707 int bytes_returned = 0;
5708 char *data_offset;
5709 __u16 params, param_offset, offset, byte_count, count;
5710
Joe Perchesb6b38f72010-04-21 03:50:45 +00005711 cFYI(1, "In SetTimes");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005712
5713SetTimesRetry:
5714 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5715 (void **) &pSMBr);
5716 if (rc)
5717 return rc;
5718
5719 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5720 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005721 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5722 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005723 name_len++; /* trailing null */
5724 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005725 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005726 name_len = strnlen(fileName, PATH_MAX);
5727 name_len++; /* trailing null */
5728 strncpy(pSMB->FileName, fileName, name_len);
5729 }
5730
5731 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005732 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005733 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005734 /* BB find max SMB PDU from sess structure BB */
5735 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005736 pSMB->MaxSetupCount = 0;
5737 pSMB->Reserved = 0;
5738 pSMB->Flags = 0;
5739 pSMB->Timeout = 0;
5740 pSMB->Reserved2 = 0;
5741 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005742 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005743 offset = param_offset + params;
5744 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5745 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5746 pSMB->DataOffset = cpu_to_le16(offset);
5747 pSMB->SetupCount = 1;
5748 pSMB->Reserved3 = 0;
5749 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5750 byte_count = 3 /* pad */ + params + count;
5751
5752 pSMB->DataCount = cpu_to_le16(count);
5753 pSMB->ParameterCount = cpu_to_le16(params);
5754 pSMB->TotalDataCount = pSMB->DataCount;
5755 pSMB->TotalParameterCount = pSMB->ParameterCount;
5756 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5757 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5758 else
5759 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5760 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005761 inc_rfc1001_len(pSMB, byte_count);
Steve French26f57362007-08-30 22:09:15 +00005762 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005763 pSMB->ByteCount = cpu_to_le16(byte_count);
5764 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5765 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005766 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005767 cFYI(1, "SetPathInfo (times) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005768
5769 cifs_buf_release(pSMB);
5770
5771 if (rc == -EAGAIN)
5772 goto SetTimesRetry;
5773
5774 return rc;
5775}
5776
5777/* Can not be used to set time stamps yet (due to old DOS time format) */
5778/* Can be used to set attributes */
5779#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5780 handling it anyway and NT4 was what we thought it would be needed for
5781 Do not delete it until we prove whether needed for Win9x though */
5782int
Steve French96daf2b2011-05-27 04:34:02 +00005783CIFSSMBSetAttrLegacy(int xid, struct cifs_tcon *tcon, char *fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005784 __u16 dos_attrs, const struct nls_table *nls_codepage)
5785{
5786 SETATTR_REQ *pSMB = NULL;
5787 SETATTR_RSP *pSMBr = NULL;
5788 int rc = 0;
5789 int bytes_returned;
5790 int name_len;
5791
Joe Perchesb6b38f72010-04-21 03:50:45 +00005792 cFYI(1, "In SetAttrLegacy");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005793
5794SetAttrLgcyRetry:
5795 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5796 (void **) &pSMBr);
5797 if (rc)
5798 return rc;
5799
5800 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5801 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005802 ConvertToUTF16((__le16 *) pSMB->fileName, fileName,
5803 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005804 name_len++; /* trailing null */
5805 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005806 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005807 name_len = strnlen(fileName, PATH_MAX);
5808 name_len++; /* trailing null */
5809 strncpy(pSMB->fileName, fileName, name_len);
5810 }
5811 pSMB->attr = cpu_to_le16(dos_attrs);
5812 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005813 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005814 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5815 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5816 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005817 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005818 cFYI(1, "Error in LegacySetAttr = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005819
5820 cifs_buf_release(pSMB);
5821
5822 if (rc == -EAGAIN)
5823 goto SetAttrLgcyRetry;
5824
5825 return rc;
5826}
5827#endif /* temporarily unneeded SetAttr legacy function */
5828
Jeff Layton654cf142009-07-09 20:02:49 -04005829static void
5830cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5831 const struct cifs_unix_set_info_args *args)
5832{
5833 u64 mode = args->mode;
5834
5835 /*
5836 * Samba server ignores set of file size to zero due to bugs in some
5837 * older clients, but we should be precise - we use SetFileSize to
5838 * set file size and do not want to truncate file size to zero
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005839 * accidentally as happened on one Samba server beta by putting
Jeff Layton654cf142009-07-09 20:02:49 -04005840 * zero instead of -1 here
5841 */
5842 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5843 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5844 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5845 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5846 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5847 data_offset->Uid = cpu_to_le64(args->uid);
5848 data_offset->Gid = cpu_to_le64(args->gid);
5849 /* better to leave device as zero when it is */
5850 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5851 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5852 data_offset->Permissions = cpu_to_le64(mode);
5853
5854 if (S_ISREG(mode))
5855 data_offset->Type = cpu_to_le32(UNIX_FILE);
5856 else if (S_ISDIR(mode))
5857 data_offset->Type = cpu_to_le32(UNIX_DIR);
5858 else if (S_ISLNK(mode))
5859 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5860 else if (S_ISCHR(mode))
5861 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5862 else if (S_ISBLK(mode))
5863 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5864 else if (S_ISFIFO(mode))
5865 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5866 else if (S_ISSOCK(mode))
5867 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5868}
5869
Linus Torvalds1da177e2005-04-16 15:20:36 -07005870int
Steve French96daf2b2011-05-27 04:34:02 +00005871CIFSSMBUnixSetFileInfo(const int xid, struct cifs_tcon *tcon,
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005872 const struct cifs_unix_set_info_args *args,
5873 u16 fid, u32 pid_of_opener)
5874{
5875 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005876 char *data_offset;
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005877 int rc = 0;
5878 u16 params, param_offset, offset, byte_count, count;
5879
Joe Perchesb6b38f72010-04-21 03:50:45 +00005880 cFYI(1, "Set Unix Info (via SetFileInfo)");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005881 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5882
5883 if (rc)
5884 return rc;
5885
5886 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5887 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5888
5889 params = 6;
5890 pSMB->MaxSetupCount = 0;
5891 pSMB->Reserved = 0;
5892 pSMB->Flags = 0;
5893 pSMB->Timeout = 0;
5894 pSMB->Reserved2 = 0;
5895 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5896 offset = param_offset + params;
5897
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005898 data_offset = (char *)pSMB +
5899 offsetof(struct smb_hdr, Protocol) + offset;
5900
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005901 count = sizeof(FILE_UNIX_BASIC_INFO);
5902
5903 pSMB->MaxParameterCount = cpu_to_le16(2);
5904 /* BB find max SMB PDU from sess */
5905 pSMB->MaxDataCount = cpu_to_le16(1000);
5906 pSMB->SetupCount = 1;
5907 pSMB->Reserved3 = 0;
5908 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5909 byte_count = 3 /* pad */ + params + count;
5910 pSMB->DataCount = cpu_to_le16(count);
5911 pSMB->ParameterCount = cpu_to_le16(params);
5912 pSMB->TotalDataCount = pSMB->DataCount;
5913 pSMB->TotalParameterCount = pSMB->ParameterCount;
5914 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5915 pSMB->DataOffset = cpu_to_le16(offset);
5916 pSMB->Fid = fid;
5917 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5918 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005919 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005920 pSMB->ByteCount = cpu_to_le16(byte_count);
5921
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005922 cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005923
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005924 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005925 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005926 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005927
5928 /* Note: On -EAGAIN error only caller can retry on handle based calls
5929 since file handle passed in no longer valid */
5930
5931 return rc;
5932}
5933
5934int
Steve French96daf2b2011-05-27 04:34:02 +00005935CIFSSMBUnixSetPathInfo(const int xid, struct cifs_tcon *tcon, char *fileName,
Jeff Layton01ea95e2009-07-09 20:02:49 -04005936 const struct cifs_unix_set_info_args *args,
5937 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005938{
5939 TRANSACTION2_SPI_REQ *pSMB = NULL;
5940 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5941 int name_len;
5942 int rc = 0;
5943 int bytes_returned = 0;
5944 FILE_UNIX_BASIC_INFO *data_offset;
5945 __u16 params, param_offset, offset, count, byte_count;
5946
Joe Perchesb6b38f72010-04-21 03:50:45 +00005947 cFYI(1, "In SetUID/GID/Mode");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005948setPermsRetry:
5949 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5950 (void **) &pSMBr);
5951 if (rc)
5952 return rc;
5953
5954 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5955 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005956 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5957 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005958 name_len++; /* trailing null */
5959 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005960 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005961 name_len = strnlen(fileName, PATH_MAX);
5962 name_len++; /* trailing null */
5963 strncpy(pSMB->FileName, fileName, name_len);
5964 }
5965
5966 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005967 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005968 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005969 /* BB find max SMB PDU from sess structure BB */
5970 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005971 pSMB->MaxSetupCount = 0;
5972 pSMB->Reserved = 0;
5973 pSMB->Flags = 0;
5974 pSMB->Timeout = 0;
5975 pSMB->Reserved2 = 0;
5976 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005977 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005978 offset = param_offset + params;
5979 data_offset =
5980 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5981 offset);
5982 memset(data_offset, 0, count);
5983 pSMB->DataOffset = cpu_to_le16(offset);
5984 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5985 pSMB->SetupCount = 1;
5986 pSMB->Reserved3 = 0;
5987 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5988 byte_count = 3 /* pad */ + params + count;
5989 pSMB->ParameterCount = cpu_to_le16(params);
5990 pSMB->DataCount = cpu_to_le16(count);
5991 pSMB->TotalParameterCount = pSMB->ParameterCount;
5992 pSMB->TotalDataCount = pSMB->DataCount;
5993 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5994 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005995 inc_rfc1001_len(pSMB, byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005996
Jeff Layton654cf142009-07-09 20:02:49 -04005997 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005998
5999 pSMB->ByteCount = cpu_to_le16(byte_count);
6000 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6001 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006002 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00006003 cFYI(1, "SetPathInfo (perms) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006004
Steve French0d817bc2008-05-22 02:02:03 +00006005 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006006 if (rc == -EAGAIN)
6007 goto setPermsRetry;
6008 return rc;
6009}
6010
Linus Torvalds1da177e2005-04-16 15:20:36 -07006011#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05006012/*
6013 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
6014 * function used by listxattr and getxattr type calls. When ea_name is set,
6015 * it looks for that attribute name and stuffs that value into the EAData
6016 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
6017 * buffer. In both cases, the return value is either the length of the
6018 * resulting data or a negative error code. If EAData is a NULL pointer then
6019 * the data isn't copied to it, but the length is returned.
6020 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006021ssize_t
Steve French96daf2b2011-05-27 04:34:02 +00006022CIFSSMBQAllEAs(const int xid, struct cifs_tcon *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05006023 const unsigned char *searchName, const unsigned char *ea_name,
6024 char *EAData, size_t buf_size,
6025 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006026{
6027 /* BB assumes one setup word */
6028 TRANSACTION2_QPI_REQ *pSMB = NULL;
6029 TRANSACTION2_QPI_RSP *pSMBr = NULL;
6030 int rc = 0;
6031 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05006032 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006033 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00006034 struct fea *temp_fea;
6035 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006036 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006037 __u16 params, byte_count, data_offset;
Jeff Layton5980fc92011-07-28 12:48:26 -04006038 unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006039
Joe Perchesb6b38f72010-04-21 03:50:45 +00006040 cFYI(1, "In Query All EAs path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006041QAllEAsRetry:
6042 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6043 (void **) &pSMBr);
6044 if (rc)
6045 return rc;
6046
6047 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05006048 list_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006049 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
6050 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05006051 list_len++; /* trailing null */
6052 list_len *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006053 } else { /* BB improve the check for buffer overruns BB */
Jeff Layton6e462b92010-02-10 16:18:26 -05006054 list_len = strnlen(searchName, PATH_MAX);
6055 list_len++; /* trailing null */
6056 strncpy(pSMB->FileName, searchName, list_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006057 }
6058
Jeff Layton6e462b92010-02-10 16:18:26 -05006059 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006060 pSMB->TotalDataCount = 0;
6061 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006062 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05006063 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006064 pSMB->MaxSetupCount = 0;
6065 pSMB->Reserved = 0;
6066 pSMB->Flags = 0;
6067 pSMB->Timeout = 0;
6068 pSMB->Reserved2 = 0;
6069 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00006070 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006071 pSMB->DataCount = 0;
6072 pSMB->DataOffset = 0;
6073 pSMB->SetupCount = 1;
6074 pSMB->Reserved3 = 0;
6075 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
6076 byte_count = params + 1 /* pad */ ;
6077 pSMB->TotalParameterCount = cpu_to_le16(params);
6078 pSMB->ParameterCount = pSMB->TotalParameterCount;
6079 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
6080 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006081 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006082 pSMB->ByteCount = cpu_to_le16(byte_count);
6083
6084 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6085 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6086 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006087 cFYI(1, "Send error in QueryAllEAs = %d", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05006088 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006089 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006090
6091
6092 /* BB also check enough total bytes returned */
6093 /* BB we need to improve the validity checking
6094 of these trans2 responses */
6095
6096 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Jeff Layton820a8032011-05-04 08:05:26 -04006097 if (rc || get_bcc(&pSMBr->hdr) < 4) {
Jeff Laytonf0d38682010-02-10 16:18:26 -05006098 rc = -EIO; /* bad smb */
6099 goto QAllEAsOut;
6100 }
6101
6102 /* check that length of list is not more than bcc */
6103 /* check that each entry does not go beyond length
6104 of list */
6105 /* check that each element of each entry does not
6106 go beyond end of list */
6107 /* validate_trans2_offsets() */
6108 /* BB check if start of smb + data_offset > &bcc+ bcc */
6109
6110 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
6111 ea_response_data = (struct fealist *)
6112 (((char *) &pSMBr->hdr.Protocol) + data_offset);
6113
Jeff Layton6e462b92010-02-10 16:18:26 -05006114 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesb6b38f72010-04-21 03:50:45 +00006115 cFYI(1, "ea length %d", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05006116 if (list_len <= 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006117 cFYI(1, "empty EA list returned from server");
Jeff Laytonf0d38682010-02-10 16:18:26 -05006118 goto QAllEAsOut;
6119 }
6120
Jeff Layton0cd126b2010-02-10 16:18:26 -05006121 /* make sure list_len doesn't go past end of SMB */
Jeff Layton690c5222011-01-20 13:36:51 -05006122 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
Jeff Layton0cd126b2010-02-10 16:18:26 -05006123 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006124 cFYI(1, "EA list appears to go beyond SMB");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006125 rc = -EIO;
6126 goto QAllEAsOut;
6127 }
6128
Jeff Laytonf0d38682010-02-10 16:18:26 -05006129 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05006130 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006131 temp_fea = ea_response_data->list;
6132 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05006133 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00006134 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006135 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006136
Jeff Layton6e462b92010-02-10 16:18:26 -05006137 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006138 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006139 /* make sure we can read name_len and value_len */
6140 if (list_len < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006141 cFYI(1, "EA entry goes beyond length of list");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006142 rc = -EIO;
6143 goto QAllEAsOut;
6144 }
6145
6146 name_len = temp_fea->name_len;
6147 value_len = le16_to_cpu(temp_fea->value_len);
6148 list_len -= name_len + 1 + value_len;
6149 if (list_len < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006150 cFYI(1, "EA entry goes beyond length of list");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006151 rc = -EIO;
6152 goto QAllEAsOut;
6153 }
6154
Jeff Layton31c05192010-02-10 16:18:26 -05006155 if (ea_name) {
Jeff Layton91d065c2011-07-26 18:23:47 -04006156 if (ea_name_len == name_len &&
Jeff Laytonac423442011-10-11 06:41:32 -04006157 memcmp(ea_name, temp_ptr, name_len) == 0) {
Jeff Layton31c05192010-02-10 16:18:26 -05006158 temp_ptr += name_len + 1;
6159 rc = value_len;
6160 if (buf_size == 0)
6161 goto QAllEAsOut;
6162 if ((size_t)value_len > buf_size) {
6163 rc = -ERANGE;
6164 goto QAllEAsOut;
6165 }
6166 memcpy(EAData, temp_ptr, value_len);
6167 goto QAllEAsOut;
6168 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006169 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05006170 /* account for prefix user. and trailing null */
6171 rc += (5 + 1 + name_len);
6172 if (rc < (int) buf_size) {
6173 memcpy(EAData, "user.", 5);
6174 EAData += 5;
6175 memcpy(EAData, temp_ptr, name_len);
6176 EAData += name_len;
6177 /* null terminate name */
6178 *EAData = 0;
6179 ++EAData;
6180 } else if (buf_size == 0) {
6181 /* skip copy - calc size only */
6182 } else {
6183 /* stop before overrun buffer */
6184 rc = -ERANGE;
6185 break;
6186 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006187 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05006188 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006189 temp_fea = (struct fea *)temp_ptr;
6190 }
6191
Jeff Layton31c05192010-02-10 16:18:26 -05006192 /* didn't find the named attribute */
6193 if (ea_name)
6194 rc = -ENODATA;
6195
Jeff Laytonf0d38682010-02-10 16:18:26 -05006196QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00006197 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006198 if (rc == -EAGAIN)
6199 goto QAllEAsRetry;
6200
6201 return (ssize_t)rc;
6202}
6203
Linus Torvalds1da177e2005-04-16 15:20:36 -07006204int
Steve French96daf2b2011-05-27 04:34:02 +00006205CIFSSMBSetEA(const int xid, struct cifs_tcon *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00006206 const char *ea_name, const void *ea_value,
6207 const __u16 ea_value_len, const struct nls_table *nls_codepage,
6208 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006209{
6210 struct smb_com_transaction2_spi_req *pSMB = NULL;
6211 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
6212 struct fealist *parm_data;
6213 int name_len;
6214 int rc = 0;
6215 int bytes_returned = 0;
6216 __u16 params, param_offset, byte_count, offset, count;
6217
Joe Perchesb6b38f72010-04-21 03:50:45 +00006218 cFYI(1, "In SetEA");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006219SetEARetry:
6220 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6221 (void **) &pSMBr);
6222 if (rc)
6223 return rc;
6224
6225 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6226 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006227 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
6228 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006229 name_len++; /* trailing null */
6230 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00006231 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006232 name_len = strnlen(fileName, PATH_MAX);
6233 name_len++; /* trailing null */
6234 strncpy(pSMB->FileName, fileName, name_len);
6235 }
6236
6237 params = 6 + name_len;
6238
6239 /* done calculating parms using name_len of file name,
6240 now use name_len to calculate length of ea name
6241 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00006242 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006243 name_len = 0;
6244 else
Steve French50c2f752007-07-13 00:33:32 +00006245 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006246
Steve Frenchdae5dbd2007-12-30 23:49:57 +00006247 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006248 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006249 /* BB find max SMB PDU from sess */
6250 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006251 pSMB->MaxSetupCount = 0;
6252 pSMB->Reserved = 0;
6253 pSMB->Flags = 0;
6254 pSMB->Timeout = 0;
6255 pSMB->Reserved2 = 0;
6256 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006257 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006258 offset = param_offset + params;
6259 pSMB->InformationLevel =
6260 cpu_to_le16(SMB_SET_FILE_EA);
6261
6262 parm_data =
6263 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
6264 offset);
6265 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6266 pSMB->DataOffset = cpu_to_le16(offset);
6267 pSMB->SetupCount = 1;
6268 pSMB->Reserved3 = 0;
6269 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6270 byte_count = 3 /* pad */ + params + count;
6271 pSMB->DataCount = cpu_to_le16(count);
6272 parm_data->list_len = cpu_to_le32(count);
6273 parm_data->list[0].EA_flags = 0;
6274 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08006275 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006276 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00006277 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00006278 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006279 parm_data->list[0].name[name_len] = 0;
6280 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
6281 /* caller ensures that ea_value_len is less than 64K but
6282 we need to ensure that it fits within the smb */
6283
Steve French50c2f752007-07-13 00:33:32 +00006284 /*BB add length check to see if it would fit in
6285 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00006286 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
6287 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00006288 memcpy(parm_data->list[0].name+name_len+1,
6289 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006290
6291 pSMB->TotalDataCount = pSMB->DataCount;
6292 pSMB->ParameterCount = cpu_to_le16(params);
6293 pSMB->TotalParameterCount = pSMB->ParameterCount;
6294 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006295 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006296 pSMB->ByteCount = cpu_to_le16(byte_count);
6297 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6298 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006299 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00006300 cFYI(1, "SetPathInfo (EA) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006301
6302 cifs_buf_release(pSMB);
6303
6304 if (rc == -EAGAIN)
6305 goto SetEARetry;
6306
6307 return rc;
6308}
Linus Torvalds1da177e2005-04-16 15:20:36 -07006309#endif
Steve French0eff0e22011-02-24 05:39:23 +00006310
6311#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */
6312/*
6313 * Years ago the kernel added a "dnotify" function for Samba server,
6314 * to allow network clients (such as Windows) to display updated
6315 * lists of files in directory listings automatically when
6316 * files are added by one user when another user has the
6317 * same directory open on their desktop. The Linux cifs kernel
6318 * client hooked into the kernel side of this interface for
6319 * the same reason, but ironically when the VFS moved from
6320 * "dnotify" to "inotify" it became harder to plug in Linux
6321 * network file system clients (the most obvious use case
6322 * for notify interfaces is when multiple users can update
6323 * the contents of the same directory - exactly what network
6324 * file systems can do) although the server (Samba) could
6325 * still use it. For the short term we leave the worker
6326 * function ifdeffed out (below) until inotify is fixed
6327 * in the VFS to make it easier to plug in network file
6328 * system clients. If inotify turns out to be permanently
6329 * incompatible for network fs clients, we could instead simply
6330 * expose this config flag by adding a future cifs (and smb2) notify ioctl.
6331 */
Steve French96daf2b2011-05-27 04:34:02 +00006332int CIFSSMBNotify(const int xid, struct cifs_tcon *tcon,
Steve French0eff0e22011-02-24 05:39:23 +00006333 const int notify_subdirs, const __u16 netfid,
6334 __u32 filter, struct file *pfile, int multishot,
6335 const struct nls_table *nls_codepage)
6336{
6337 int rc = 0;
6338 struct smb_com_transaction_change_notify_req *pSMB = NULL;
6339 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
6340 struct dir_notify_req *dnotify_req;
6341 int bytes_returned;
6342
6343 cFYI(1, "In CIFSSMBNotify for file handle %d", (int)netfid);
6344 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
6345 (void **) &pSMBr);
6346 if (rc)
6347 return rc;
6348
6349 pSMB->TotalParameterCount = 0 ;
6350 pSMB->TotalDataCount = 0;
6351 pSMB->MaxParameterCount = cpu_to_le32(2);
Jeff Laytonc974bef2011-10-11 06:41:32 -04006352 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Steve French0eff0e22011-02-24 05:39:23 +00006353 pSMB->MaxSetupCount = 4;
6354 pSMB->Reserved = 0;
6355 pSMB->ParameterOffset = 0;
6356 pSMB->DataCount = 0;
6357 pSMB->DataOffset = 0;
6358 pSMB->SetupCount = 4; /* single byte does not need le conversion */
6359 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
6360 pSMB->ParameterCount = pSMB->TotalParameterCount;
6361 if (notify_subdirs)
6362 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
6363 pSMB->Reserved2 = 0;
6364 pSMB->CompletionFilter = cpu_to_le32(filter);
6365 pSMB->Fid = netfid; /* file handle always le */
6366 pSMB->ByteCount = 0;
6367
6368 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6369 (struct smb_hdr *)pSMBr, &bytes_returned,
6370 CIFS_ASYNC_OP);
6371 if (rc) {
6372 cFYI(1, "Error in Notify = %d", rc);
6373 } else {
6374 /* Add file to outstanding requests */
6375 /* BB change to kmem cache alloc */
6376 dnotify_req = kmalloc(
6377 sizeof(struct dir_notify_req),
6378 GFP_KERNEL);
6379 if (dnotify_req) {
6380 dnotify_req->Pid = pSMB->hdr.Pid;
6381 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
6382 dnotify_req->Mid = pSMB->hdr.Mid;
6383 dnotify_req->Tid = pSMB->hdr.Tid;
6384 dnotify_req->Uid = pSMB->hdr.Uid;
6385 dnotify_req->netfid = netfid;
6386 dnotify_req->pfile = pfile;
6387 dnotify_req->filter = filter;
6388 dnotify_req->multishot = multishot;
6389 spin_lock(&GlobalMid_Lock);
6390 list_add_tail(&dnotify_req->lhead,
6391 &GlobalDnotifyReqList);
6392 spin_unlock(&GlobalMid_Lock);
6393 } else
6394 rc = -ENOMEM;
6395 }
6396 cifs_buf_release(pSMB);
6397 return rc;
6398}
6399#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */