blob: 7a3b4a3b113b5a2827d3fd08bcef95094c79c1ba [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 Layton3cf003c2012-07-11 09:09:36 -040089#ifdef CONFIG_HIGHMEM
90/*
91 * On arches that have high memory, kmap address space is limited. By
92 * serializing the kmap operations on those arches, we ensure that we don't
93 * end up with a bunch of threads in writeback with partially mapped page
94 * arrays, stuck waiting for kmap to come back. That situation prevents
95 * progress and can deadlock.
96 */
97static DEFINE_MUTEX(cifs_kmap_mutex);
98
99static inline void
100cifs_kmap_lock(void)
101{
102 mutex_lock(&cifs_kmap_mutex);
103}
104
105static inline void
106cifs_kmap_unlock(void)
107{
108 mutex_unlock(&cifs_kmap_mutex);
109}
110#else /* !CONFIG_HIGHMEM */
111#define cifs_kmap_lock() do { ; } while(0)
112#define cifs_kmap_unlock() do { ; } while(0)
113#endif /* CONFIG_HIGHMEM */
Jeff Laytone28bc5b2011-10-19 15:30:07 -0400114
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115/* Mark as invalid, all open files on tree connections since they
116 were closed when session to server was lost */
Steve French96daf2b2011-05-27 04:34:02 +0000117static void mark_open_files_invalid(struct cifs_tcon *pTcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118{
119 struct cifsFileInfo *open_file = NULL;
Steve French790fe572007-07-07 19:25:05 +0000120 struct list_head *tmp;
121 struct list_head *tmp1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122
123/* list all files open on tree connection and mark them invalid */
Jeff Layton44772882010-10-15 15:34:03 -0400124 spin_lock(&cifs_file_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125 list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
Steve French790fe572007-07-07 19:25:05 +0000126 open_file = list_entry(tmp, struct cifsFileInfo, tlist);
Steve Frenchad8b15f2008-08-08 21:10:16 +0000127 open_file->invalidHandle = true;
Jeff Layton3bc303c2009-09-21 06:47:50 -0400128 open_file->oplock_break_cancelled = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129 }
Jeff Layton44772882010-10-15 15:34:03 -0400130 spin_unlock(&cifs_file_list_lock);
Steve French09d1db52005-04-28 22:41:08 -0700131 /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
132 to this tcon */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133}
134
Jeff Layton9162ab22009-09-03 12:07:17 -0400135/* reconnect the socket, tcon, and smb session if needed */
136static int
Steve French96daf2b2011-05-27 04:34:02 +0000137cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
Jeff Layton9162ab22009-09-03 12:07:17 -0400138{
Jeff Laytonc4a55342011-07-28 12:40:36 -0400139 int rc;
Steve French96daf2b2011-05-27 04:34:02 +0000140 struct cifs_ses *ses;
Jeff Layton9162ab22009-09-03 12:07:17 -0400141 struct TCP_Server_Info *server;
142 struct nls_table *nls_codepage;
143
144 /*
145 * SMBs NegProt, SessSetup, uLogoff do not have tcon yet so check for
146 * tcp and smb session status done differently for those three - in the
147 * calling routine
148 */
149 if (!tcon)
150 return 0;
151
152 ses = tcon->ses;
153 server = ses->server;
154
155 /*
156 * only tree disconnect, open, and write, (and ulogoff which does not
157 * have tcon) are allowed as we start force umount
158 */
159 if (tcon->tidStatus == CifsExiting) {
160 if (smb_command != SMB_COM_WRITE_ANDX &&
161 smb_command != SMB_COM_OPEN_ANDX &&
162 smb_command != SMB_COM_TREE_DISCONNECT) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000163 cFYI(1, "can not send cmd %d while umounting",
164 smb_command);
Jeff Layton9162ab22009-09-03 12:07:17 -0400165 return -ENODEV;
166 }
167 }
168
Jeff Layton9162ab22009-09-03 12:07:17 -0400169 /*
170 * Give demultiplex thread up to 10 seconds to reconnect, should be
171 * greater than cifs socket timeout which is 7 seconds
172 */
173 while (server->tcpStatus == CifsNeedReconnect) {
174 wait_event_interruptible_timeout(server->response_q,
Steve Frenchfd88ce92011-04-12 01:01:14 +0000175 (server->tcpStatus != CifsNeedReconnect), 10 * HZ);
Jeff Layton9162ab22009-09-03 12:07:17 -0400176
Steve Frenchfd88ce92011-04-12 01:01:14 +0000177 /* are we still trying to reconnect? */
Jeff Layton9162ab22009-09-03 12:07:17 -0400178 if (server->tcpStatus != CifsNeedReconnect)
179 break;
180
181 /*
182 * on "soft" mounts we wait once. Hard mounts keep
183 * retrying until process is killed or server comes
184 * back on-line
185 */
Jeff Laytond4025392011-02-07 08:54:35 -0500186 if (!tcon->retry) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000187 cFYI(1, "gave up waiting on reconnect in smb_init");
Jeff Layton9162ab22009-09-03 12:07:17 -0400188 return -EHOSTDOWN;
189 }
190 }
191
192 if (!ses->need_reconnect && !tcon->need_reconnect)
193 return 0;
194
195 nls_codepage = load_nls_default();
196
197 /*
198 * need to prevent multiple threads trying to simultaneously
199 * reconnect the same SMB session
200 */
Steve Frenchd7b619c2010-02-25 05:36:46 +0000201 mutex_lock(&ses->session_mutex);
Jeff Layton198b5682010-04-24 07:57:48 -0400202 rc = cifs_negotiate_protocol(0, ses);
203 if (rc == 0 && ses->need_reconnect)
Jeff Layton9162ab22009-09-03 12:07:17 -0400204 rc = cifs_setup_session(0, ses, nls_codepage);
205
206 /* do we need to reconnect tcon? */
207 if (rc || !tcon->need_reconnect) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000208 mutex_unlock(&ses->session_mutex);
Jeff Layton9162ab22009-09-03 12:07:17 -0400209 goto out;
210 }
211
212 mark_open_files_invalid(tcon);
213 rc = CIFSTCon(0, ses, tcon->treeName, tcon, nls_codepage);
Steve Frenchd7b619c2010-02-25 05:36:46 +0000214 mutex_unlock(&ses->session_mutex);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000215 cFYI(1, "reconnect tcon rc = %d", rc);
Jeff Layton9162ab22009-09-03 12:07:17 -0400216
217 if (rc)
218 goto out;
219
220 /*
221 * FIXME: check if wsize needs updated due to negotiated smb buffer
222 * size shrinking
223 */
224 atomic_inc(&tconInfoReconnectCount);
225
226 /* tell server Unix caps we support */
227 if (ses->capabilities & CAP_UNIX)
228 reset_cifs_unix_caps(0, tcon, NULL, NULL);
229
230 /*
231 * Removed call to reopen open files here. It is safer (and faster) to
232 * reopen files one at a time as needed in read and write.
233 *
234 * FIXME: what about file locks? don't we need to reclaim them ASAP?
235 */
236
237out:
238 /*
239 * Check if handle based operation so we know whether we can continue
240 * or not without returning to caller to reset file handle
241 */
242 switch (smb_command) {
243 case SMB_COM_READ_ANDX:
244 case SMB_COM_WRITE_ANDX:
245 case SMB_COM_CLOSE:
246 case SMB_COM_FIND_CLOSE2:
247 case SMB_COM_LOCKING_ANDX:
248 rc = -EAGAIN;
249 }
250
251 unload_nls(nls_codepage);
252 return rc;
253}
254
Steve Frenchad7a2922008-02-07 23:25:02 +0000255/* Allocate and return pointer to an SMB request buffer, and set basic
256 SMB information in the SMB header. If the return code is zero, this
257 function must have filled in request_buf pointer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258static int
Steve French96daf2b2011-05-27 04:34:02 +0000259small_smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000260 void **request_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261{
Jeff Laytonf5695992010-09-29 15:27:08 -0400262 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263
Jeff Layton9162ab22009-09-03 12:07:17 -0400264 rc = cifs_reconnect_tcon(tcon, smb_command);
Steve French790fe572007-07-07 19:25:05 +0000265 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266 return rc;
267
268 *request_buf = cifs_small_buf_get();
269 if (*request_buf == NULL) {
270 /* BB should we add a retry in here if not a writepage? */
271 return -ENOMEM;
272 }
273
Steve French63135e02007-07-17 17:34:02 +0000274 header_assemble((struct smb_hdr *) *request_buf, smb_command,
Steve Frenchc18c8422007-07-18 23:21:09 +0000275 tcon, wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276
Steve French790fe572007-07-07 19:25:05 +0000277 if (tcon != NULL)
278 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700279
Jeff Laytonf5695992010-09-29 15:27:08 -0400280 return 0;
Steve French5815449d2006-02-14 01:36:20 +0000281}
282
Steve French12b3b8f2006-02-09 21:12:47 +0000283int
Steve French50c2f752007-07-13 00:33:32 +0000284small_smb_init_no_tc(const int smb_command, const int wct,
Steve French96daf2b2011-05-27 04:34:02 +0000285 struct cifs_ses *ses, void **request_buf)
Steve French12b3b8f2006-02-09 21:12:47 +0000286{
287 int rc;
Steve French50c2f752007-07-13 00:33:32 +0000288 struct smb_hdr *buffer;
Steve French12b3b8f2006-02-09 21:12:47 +0000289
Steve French5815449d2006-02-14 01:36:20 +0000290 rc = small_smb_init(smb_command, wct, NULL, request_buf);
Steve French790fe572007-07-07 19:25:05 +0000291 if (rc)
Steve French12b3b8f2006-02-09 21:12:47 +0000292 return rc;
293
Steve French04fdabe2006-02-10 05:52:50 +0000294 buffer = (struct smb_hdr *)*request_buf;
Pavel Shilovsky88257362012-05-23 14:01:59 +0400295 buffer->Mid = get_next_mid(ses->server);
Steve French12b3b8f2006-02-09 21:12:47 +0000296 if (ses->capabilities & CAP_UNICODE)
297 buffer->Flags2 |= SMBFLG2_UNICODE;
Steve French04fdabe2006-02-10 05:52:50 +0000298 if (ses->capabilities & CAP_STATUS32)
Steve French12b3b8f2006-02-09 21:12:47 +0000299 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
300
301 /* uid, tid can stay at zero as set in header assemble */
302
Steve French50c2f752007-07-13 00:33:32 +0000303 /* BB add support for turning on the signing when
Steve French12b3b8f2006-02-09 21:12:47 +0000304 this function is used after 1st of session setup requests */
305
306 return rc;
307}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308
309/* If the return code is zero, this function must fill in request_buf pointer */
310static int
Steve French96daf2b2011-05-27 04:34:02 +0000311__smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400312 void **request_buf, void **response_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 *request_buf = cifs_buf_get();
315 if (*request_buf == NULL) {
316 /* BB should we add a retry in here if not a writepage? */
317 return -ENOMEM;
318 }
319 /* Although the original thought was we needed the response buf for */
320 /* potential retries of smb operations it turns out we can determine */
321 /* from the mid flags when the request buffer can be resent without */
322 /* having to use a second distinct buffer for the response */
Steve French790fe572007-07-07 19:25:05 +0000323 if (response_buf)
Steve French50c2f752007-07-13 00:33:32 +0000324 *response_buf = *request_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325
326 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000327 wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328
Steve French790fe572007-07-07 19:25:05 +0000329 if (tcon != NULL)
330 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700331
Jeff Laytonf5695992010-09-29 15:27:08 -0400332 return 0;
333}
334
335/* If the return code is zero, this function must fill in request_buf pointer */
336static int
Steve French96daf2b2011-05-27 04:34:02 +0000337smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400338 void **request_buf, void **response_buf)
339{
340 int rc;
341
342 rc = cifs_reconnect_tcon(tcon, smb_command);
343 if (rc)
344 return rc;
345
346 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
347}
348
349static int
Steve French96daf2b2011-05-27 04:34:02 +0000350smb_init_no_reconnect(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400351 void **request_buf, void **response_buf)
352{
353 if (tcon->ses->need_reconnect || tcon->need_reconnect)
354 return -EHOSTDOWN;
355
356 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357}
358
Steve French50c2f752007-07-13 00:33:32 +0000359static int validate_t2(struct smb_t2_rsp *pSMB)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360{
Jeff Layton12df83c2011-01-20 13:36:51 -0500361 unsigned int total_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362
Jeff Layton12df83c2011-01-20 13:36:51 -0500363 /* check for plausible wct */
364 if (pSMB->hdr.WordCount < 10)
365 goto vt2_err;
366
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367 /* check for parm and data offset going beyond end of smb */
Jeff Layton12df83c2011-01-20 13:36:51 -0500368 if (get_unaligned_le16(&pSMB->t2_rsp.ParameterOffset) > 1024 ||
369 get_unaligned_le16(&pSMB->t2_rsp.DataOffset) > 1024)
370 goto vt2_err;
371
Jeff Layton12df83c2011-01-20 13:36:51 -0500372 total_size = get_unaligned_le16(&pSMB->t2_rsp.ParameterCount);
373 if (total_size >= 512)
374 goto vt2_err;
375
Jeff Laytonfd5707e2011-03-31 17:22:07 -0400376 /* check that bcc is at least as big as parms + data, and that it is
377 * less than negotiated smb buffer
378 */
Jeff Layton12df83c2011-01-20 13:36:51 -0500379 total_size += get_unaligned_le16(&pSMB->t2_rsp.DataCount);
380 if (total_size > get_bcc(&pSMB->hdr) ||
381 total_size >= CIFSMaxBufSize + MAX_CIFS_HDR_SIZE)
382 goto vt2_err;
383
384 return 0;
385vt2_err:
Steve French50c2f752007-07-13 00:33:32 +0000386 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387 sizeof(struct smb_t2_rsp) + 16);
Jeff Layton12df83c2011-01-20 13:36:51 -0500388 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389}
Jeff Layton690c5222011-01-20 13:36:51 -0500390
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000391static inline void inc_rfc1001_len(void *pSMB, int count)
392{
393 struct smb_hdr *hdr = (struct smb_hdr *)pSMB;
394
395 be32_add_cpu(&hdr->smb_buf_length, count);
396}
397
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398int
Pavel Shilovsky286170a2012-05-25 10:43:58 +0400399CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400{
401 NEGOTIATE_REQ *pSMB;
402 NEGOTIATE_RSP *pSMBr;
403 int rc = 0;
404 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000405 int i;
Steve French50c2f752007-07-13 00:33:32 +0000406 struct TCP_Server_Info *server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 u16 count;
Steve French750d1152006-06-27 06:28:30 +0000408 unsigned int secFlags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409
Steve French790fe572007-07-07 19:25:05 +0000410 if (ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411 server = ses->server;
412 else {
413 rc = -EIO;
414 return rc;
415 }
416 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
417 (void **) &pSMB, (void **) &pSMBr);
418 if (rc)
419 return rc;
Steve French750d1152006-06-27 06:28:30 +0000420
421 /* if any of auth flags (ie not sign or seal) are overriden use them */
Steve French790fe572007-07-07 19:25:05 +0000422 if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
Steve French762e5ab2007-06-28 18:41:42 +0000423 secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
Steve French750d1152006-06-27 06:28:30 +0000424 else /* if override flags set only sign/seal OR them with global auth */
Jeff Layton04912d62010-04-24 07:57:45 -0400425 secFlags = global_secflags | ses->overrideSecFlg;
Steve French750d1152006-06-27 06:28:30 +0000426
Joe Perchesb6b38f72010-04-21 03:50:45 +0000427 cFYI(1, "secFlags 0x%x", secFlags);
Steve Frenchf40c5622006-06-28 00:13:38 +0000428
Pavel Shilovsky88257362012-05-23 14:01:59 +0400429 pSMB->hdr.Mid = get_next_mid(server);
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000430 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
Steve Frencha0136892007-10-04 20:05:09 +0000431
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000432 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
Steve French254e55e2006-06-04 05:53:15 +0000433 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Steve Frencha0136892007-10-04 20:05:09 +0000434 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000435 cFYI(1, "Kerberos only mechanism, enable extended security");
Steve Frencha0136892007-10-04 20:05:09 +0000436 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Jeff Laytonb4d6fcf2011-01-07 11:30:28 -0500437 } else if ((secFlags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP)
Steve Frenchac683922009-05-06 04:16:04 +0000438 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
439 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_NTLMSSP) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000440 cFYI(1, "NTLMSSP only mechanism, enable extended security");
Steve Frenchac683922009-05-06 04:16:04 +0000441 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
442 }
Steve French50c2f752007-07-13 00:33:32 +0000443
Steve French39798772006-05-31 22:40:51 +0000444 count = 0;
Steve French50c2f752007-07-13 00:33:32 +0000445 for (i = 0; i < CIFS_NUM_PROT; i++) {
Steve French39798772006-05-31 22:40:51 +0000446 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
447 count += strlen(protocols[i].name) + 1;
448 /* null at end of source and target buffers anyway */
449 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000450 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 pSMB->ByteCount = cpu_to_le16(count);
452
453 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
454 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French50c2f752007-07-13 00:33:32 +0000455 if (rc != 0)
Steve French254e55e2006-06-04 05:53:15 +0000456 goto neg_err_exit;
457
Jeff Layton9bf67e52010-04-24 07:57:46 -0400458 server->dialect = le16_to_cpu(pSMBr->DialectIndex);
459 cFYI(1, "Dialect: %d", server->dialect);
Steve French254e55e2006-06-04 05:53:15 +0000460 /* Check wct = 1 error case */
Jeff Layton9bf67e52010-04-24 07:57:46 -0400461 if ((pSMBr->hdr.WordCount < 13) || (server->dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000462 /* core returns wct = 1, but we do not ask for core - otherwise
Steve French50c2f752007-07-13 00:33:32 +0000463 small wct just comes when dialect index is -1 indicating we
Steve French254e55e2006-06-04 05:53:15 +0000464 could not negotiate a common dialect */
465 rc = -EOPNOTSUPP;
466 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000467#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French790fe572007-07-07 19:25:05 +0000468 } else if ((pSMBr->hdr.WordCount == 13)
Jeff Layton9bf67e52010-04-24 07:57:46 -0400469 && ((server->dialect == LANMAN_PROT)
470 || (server->dialect == LANMAN2_PROT))) {
Steve Frenchb815f1e2006-10-02 05:53:29 +0000471 __s16 tmp;
Steve French50c2f752007-07-13 00:33:32 +0000472 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
Steve French254e55e2006-06-04 05:53:15 +0000473
Steve French790fe572007-07-07 19:25:05 +0000474 if ((secFlags & CIFSSEC_MAY_LANMAN) ||
Steve French750d1152006-06-27 06:28:30 +0000475 (secFlags & CIFSSEC_MAY_PLNTXT))
Steve French254e55e2006-06-04 05:53:15 +0000476 server->secType = LANMAN;
477 else {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000478 cERROR(1, "mount failed weak security disabled"
479 " in /proc/fs/cifs/SecurityFlags");
Steve French39798772006-05-31 22:40:51 +0000480 rc = -EOPNOTSUPP;
481 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000482 }
Pavel Shilovsky286170a2012-05-25 10:43:58 +0400483 server->sec_mode = le16_to_cpu(rsp->SecurityMode);
Pavel Shilovsky10b9b982012-03-20 12:55:09 +0300484 server->maxReq = min_t(unsigned int,
485 le16_to_cpu(rsp->MaxMpxCount),
486 cifs_max_pending);
Pavel Shilovsky45275782012-05-17 17:53:29 +0400487 set_credits(server, server->maxReq);
Jeff Laytonc974bef2011-10-11 06:41:32 -0400488 server->maxBuf = le16_to_cpu(rsp->MaxBufSize);
Steve Frencheca6acf2009-02-20 05:43:09 +0000489 server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
Steve French254e55e2006-06-04 05:53:15 +0000490 /* even though we do not use raw we might as well set this
491 accurately, in case we ever find a need for it */
Steve French790fe572007-07-07 19:25:05 +0000492 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
Steve Frencheca6acf2009-02-20 05:43:09 +0000493 server->max_rw = 0xFF00;
Steve French254e55e2006-06-04 05:53:15 +0000494 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
495 } else {
Steve Frencheca6acf2009-02-20 05:43:09 +0000496 server->max_rw = 0;/* do not need to use raw anyway */
Steve French254e55e2006-06-04 05:53:15 +0000497 server->capabilities = CAP_MPX_MODE;
498 }
Steve Frenchb815f1e2006-10-02 05:53:29 +0000499 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
Steve French1a70d652006-10-02 05:59:18 +0000500 if (tmp == -1) {
Steve French25ee4a92006-09-30 00:54:23 +0000501 /* OS/2 often does not set timezone therefore
502 * we must use server time to calc time zone.
Steve Frenchb815f1e2006-10-02 05:53:29 +0000503 * Could deviate slightly from the right zone.
504 * Smallest defined timezone difference is 15 minutes
505 * (i.e. Nepal). Rounding up/down is done to match
506 * this requirement.
Steve French25ee4a92006-09-30 00:54:23 +0000507 */
Steve Frenchb815f1e2006-10-02 05:53:29 +0000508 int val, seconds, remain, result;
Steve French25ee4a92006-09-30 00:54:23 +0000509 struct timespec ts, utc;
510 utc = CURRENT_TIME;
Jeff Laytonc4a2c082009-05-27 09:37:33 -0400511 ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
512 rsp->SrvTime.Time, 0);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000513 cFYI(1, "SrvTime %d sec since 1970 (utc: %d) diff: %d",
Steve French50c2f752007-07-13 00:33:32 +0000514 (int)ts.tv_sec, (int)utc.tv_sec,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000515 (int)(utc.tv_sec - ts.tv_sec));
Steve Frenchb815f1e2006-10-02 05:53:29 +0000516 val = (int)(utc.tv_sec - ts.tv_sec);
Andre Haupt8594c152007-08-30 20:18:41 +0000517 seconds = abs(val);
Steve French947a5062006-10-02 05:55:25 +0000518 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
Steve Frenchb815f1e2006-10-02 05:53:29 +0000519 remain = seconds % MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000520 if (remain >= (MIN_TZ_ADJ / 2))
Steve Frenchb815f1e2006-10-02 05:53:29 +0000521 result += MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000522 if (val < 0)
Steve Frenchad7a2922008-02-07 23:25:02 +0000523 result = -result;
Steve Frenchb815f1e2006-10-02 05:53:29 +0000524 server->timeAdj = result;
Steve French25ee4a92006-09-30 00:54:23 +0000525 } else {
Steve Frenchb815f1e2006-10-02 05:53:29 +0000526 server->timeAdj = (int)tmp;
527 server->timeAdj *= 60; /* also in seconds */
Steve French25ee4a92006-09-30 00:54:23 +0000528 }
Joe Perchesb6b38f72010-04-21 03:50:45 +0000529 cFYI(1, "server->timeAdj: %d seconds", server->timeAdj);
Steve French25ee4a92006-09-30 00:54:23 +0000530
Steve French39798772006-05-31 22:40:51 +0000531
Steve French254e55e2006-06-04 05:53:15 +0000532 /* BB get server time for time conversions and add
Steve French50c2f752007-07-13 00:33:32 +0000533 code to use it and timezone since this is not UTC */
Steve French39798772006-05-31 22:40:51 +0000534
Steve French50c2f752007-07-13 00:33:32 +0000535 if (rsp->EncryptionKeyLength ==
Steve French25ee4a92006-09-30 00:54:23 +0000536 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500537 memcpy(ses->server->cryptkey, rsp->EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000538 CIFS_CRYPTO_KEY_SIZE);
Steve French96daf2b2011-05-27 04:34:02 +0000539 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
Steve French254e55e2006-06-04 05:53:15 +0000540 rc = -EIO; /* need cryptkey unless plain text */
541 goto neg_err_exit;
542 }
Steve French39798772006-05-31 22:40:51 +0000543
Steve Frenchf19159d2010-04-21 04:12:10 +0000544 cFYI(1, "LANMAN negotiated");
Steve French254e55e2006-06-04 05:53:15 +0000545 /* we will not end up setting signing flags - as no signing
546 was in LANMAN and server did not return the flags on */
547 goto signing_check;
Steve French7c7b25b2006-06-01 19:20:10 +0000548#else /* weak security disabled */
Steve French790fe572007-07-07 19:25:05 +0000549 } else if (pSMBr->hdr.WordCount == 13) {
Steve Frenchf19159d2010-04-21 04:12:10 +0000550 cERROR(1, "mount failed, cifs module not built "
551 "with CIFS_WEAK_PW_HASH support");
Dan Carpenter8212cf72010-03-15 11:22:26 +0300552 rc = -EOPNOTSUPP;
Steve French7c7b25b2006-06-01 19:20:10 +0000553#endif /* WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000554 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000555 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000556 /* unknown wct */
557 rc = -EOPNOTSUPP;
558 goto neg_err_exit;
559 }
560 /* else wct == 17 NTLM */
Steve French96daf2b2011-05-27 04:34:02 +0000561 server->sec_mode = pSMBr->SecurityMode;
562 if ((server->sec_mode & SECMODE_USER) == 0)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000563 cFYI(1, "share mode security");
Steve French39798772006-05-31 22:40:51 +0000564
Steve French96daf2b2011-05-27 04:34:02 +0000565 if ((server->sec_mode & SECMODE_PW_ENCRYPT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000566#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French750d1152006-06-27 06:28:30 +0000567 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000568#endif /* CIFS_WEAK_PW_HASH */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000569 cERROR(1, "Server requests plain text password"
570 " but client support disabled");
Steve French9312f672006-06-04 22:21:07 +0000571
Steve French790fe572007-07-07 19:25:05 +0000572 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
Steve French254e55e2006-06-04 05:53:15 +0000573 server->secType = NTLMv2;
Steve French790fe572007-07-07 19:25:05 +0000574 else if (secFlags & CIFSSEC_MAY_NTLM)
Steve French254e55e2006-06-04 05:53:15 +0000575 server->secType = NTLM;
Steve French790fe572007-07-07 19:25:05 +0000576 else if (secFlags & CIFSSEC_MAY_NTLMV2)
Steve Frenchf40c5622006-06-28 00:13:38 +0000577 server->secType = NTLMv2;
Steve Frencha0136892007-10-04 20:05:09 +0000578 else if (secFlags & CIFSSEC_MAY_KRB5)
579 server->secType = Kerberos;
Steve Frenchac683922009-05-06 04:16:04 +0000580 else if (secFlags & CIFSSEC_MAY_NTLMSSP)
Steve Frenchf46c7232009-06-25 03:04:20 +0000581 server->secType = RawNTLMSSP;
Steve Frencha0136892007-10-04 20:05:09 +0000582 else if (secFlags & CIFSSEC_MAY_LANMAN)
583 server->secType = LANMAN;
Steve Frencha0136892007-10-04 20:05:09 +0000584 else {
585 rc = -EOPNOTSUPP;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000586 cERROR(1, "Invalid security type");
Steve Frencha0136892007-10-04 20:05:09 +0000587 goto neg_err_exit;
588 }
589 /* else ... any others ...? */
Steve French7c7b25b2006-06-01 19:20:10 +0000590
Steve French254e55e2006-06-04 05:53:15 +0000591 /* one byte, so no need to convert this or EncryptionKeyLen from
592 little endian */
Pavel Shilovsky10b9b982012-03-20 12:55:09 +0300593 server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount),
594 cifs_max_pending);
Pavel Shilovsky45275782012-05-17 17:53:29 +0400595 set_credits(server, server->maxReq);
Steve French254e55e2006-06-04 05:53:15 +0000596 /* probably no need to store and check maxvcs */
Jeff Laytonc974bef2011-10-11 06:41:32 -0400597 server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize);
Steve Frencheca6acf2009-02-20 05:43:09 +0000598 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000599 cFYI(DBG2, "Max buf = %d", ses->server->maxBuf);
Steve French254e55e2006-06-04 05:53:15 +0000600 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e2006-10-02 05:53:29 +0000601 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
602 server->timeAdj *= 60;
Steve French254e55e2006-06-04 05:53:15 +0000603 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500604 memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000605 CIFS_CRYPTO_KEY_SIZE);
Steve French07cc6cf2011-05-27 04:12:29 +0000606 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC ||
607 server->capabilities & CAP_EXTENDED_SECURITY) &&
608 (pSMBr->EncryptionKeyLength == 0)) {
Steve French254e55e2006-06-04 05:53:15 +0000609 /* decode security blob */
Jeff Layton820a8032011-05-04 08:05:26 -0400610 count = get_bcc(&pSMBr->hdr);
Jeff Laytone187e442007-10-16 17:10:44 +0000611 if (count < 16) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 rc = -EIO;
Jeff Laytone187e442007-10-16 17:10:44 +0000613 goto neg_err_exit;
614 }
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530615 spin_lock(&cifs_tcp_ses_lock);
Jeff Laytone7ddee92008-11-14 13:44:38 -0500616 if (server->srv_count > 1) {
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530617 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000618 if (memcmp(server->server_GUID,
619 pSMBr->u.extended_response.
620 GUID, 16) != 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000621 cFYI(1, "server UID changed");
Steve French254e55e2006-06-04 05:53:15 +0000622 memcpy(server->server_GUID,
Jeff Laytone187e442007-10-16 17:10:44 +0000623 pSMBr->u.extended_response.GUID,
624 16);
625 }
Jeff Laytone7ddee92008-11-14 13:44:38 -0500626 } else {
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530627 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000628 memcpy(server->server_GUID,
629 pSMBr->u.extended_response.GUID, 16);
Jeff Laytone7ddee92008-11-14 13:44:38 -0500630 }
Jeff Laytone187e442007-10-16 17:10:44 +0000631
632 if (count == 16) {
633 server->secType = RawNTLMSSP;
Steve French254e55e2006-06-04 05:53:15 +0000634 } else {
635 rc = decode_negTokenInit(pSMBr->u.extended_response.
Jeff Layton26efa0b2010-04-24 07:57:49 -0400636 SecurityBlob, count - 16,
637 server);
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000638 if (rc == 1)
Jeff Laytone5459372007-11-03 05:11:06 +0000639 rc = 0;
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000640 else
Steve French254e55e2006-06-04 05:53:15 +0000641 rc = -EINVAL;
Shirish Pargaonkar2b149f12010-09-18 22:02:18 -0500642 if (server->secType == Kerberos) {
643 if (!server->sec_kerberos &&
644 !server->sec_mskerberos)
645 rc = -EOPNOTSUPP;
646 } else if (server->secType == RawNTLMSSP) {
647 if (!server->sec_ntlmssp)
648 rc = -EOPNOTSUPP;
649 } else
650 rc = -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651 }
Steve French96daf2b2011-05-27 04:34:02 +0000652 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
Steve French07cc6cf2011-05-27 04:12:29 +0000653 rc = -EIO; /* no crypt key only if plain text pwd */
654 goto neg_err_exit;
Steve French254e55e2006-06-04 05:53:15 +0000655 } else
656 server->capabilities &= ~CAP_EXTENDED_SECURITY;
657
Steve French6344a422006-06-12 04:18:35 +0000658#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French254e55e2006-06-04 05:53:15 +0000659signing_check:
Steve French6344a422006-06-12 04:18:35 +0000660#endif
Steve French762e5ab2007-06-28 18:41:42 +0000661 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
662 /* MUST_SIGN already includes the MAY_SIGN FLAG
663 so if this is zero it means that signing is disabled */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000664 cFYI(1, "Signing disabled");
Steve French96daf2b2011-05-27 04:34:02 +0000665 if (server->sec_mode & SECMODE_SIGN_REQUIRED) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000666 cERROR(1, "Server requires "
Jeff Layton7111d212007-10-16 16:50:25 +0000667 "packet signing to be enabled in "
Joe Perchesb6b38f72010-04-21 03:50:45 +0000668 "/proc/fs/cifs/SecurityFlags.");
Steve Frenchabb63d62007-10-18 02:58:40 +0000669 rc = -EOPNOTSUPP;
670 }
Steve French96daf2b2011-05-27 04:34:02 +0000671 server->sec_mode &=
Steve French254e55e2006-06-04 05:53:15 +0000672 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Steve French762e5ab2007-06-28 18:41:42 +0000673 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
674 /* signing required */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000675 cFYI(1, "Must sign - secFlags 0x%x", secFlags);
Steve French96daf2b2011-05-27 04:34:02 +0000676 if ((server->sec_mode &
Steve French762e5ab2007-06-28 18:41:42 +0000677 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000678 cERROR(1, "signing required but server lacks support");
Jeff38c10a12007-07-06 21:10:07 +0000679 rc = -EOPNOTSUPP;
Steve French762e5ab2007-06-28 18:41:42 +0000680 } else
Steve French96daf2b2011-05-27 04:34:02 +0000681 server->sec_mode |= SECMODE_SIGN_REQUIRED;
Steve French762e5ab2007-06-28 18:41:42 +0000682 } else {
683 /* signing optional ie CIFSSEC_MAY_SIGN */
Steve French96daf2b2011-05-27 04:34:02 +0000684 if ((server->sec_mode & SECMODE_SIGN_REQUIRED) == 0)
685 server->sec_mode &=
Steve French254e55e2006-06-04 05:53:15 +0000686 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 }
Steve French50c2f752007-07-13 00:33:32 +0000688
689neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700690 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000691
Joe Perchesb6b38f72010-04-21 03:50:45 +0000692 cFYI(1, "negprot rc %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 return rc;
694}
695
696int
Pavel Shilovsky2e6e02a2012-05-25 11:11:39 +0400697CIFSSMBTDis(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698{
699 struct smb_hdr *smb_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701
Joe Perchesb6b38f72010-04-21 03:50:45 +0000702 cFYI(1, "In tree disconnect");
Jeff Laytonf1987b42008-11-15 11:12:47 -0500703
704 /* BB: do we need to check this? These should never be NULL. */
705 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
706 return -EIO;
707
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 /*
Jeff Laytonf1987b42008-11-15 11:12:47 -0500709 * No need to return error on this operation if tid invalidated and
710 * closed on server already e.g. due to tcp session crashing. Also,
711 * the tcon is no longer on the list, so no need to take lock before
712 * checking this.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 */
Steve French268875b2009-06-25 00:29:21 +0000714 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
Steve French50c2f752007-07-13 00:33:32 +0000715 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716
Steve French50c2f752007-07-13 00:33:32 +0000717 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700718 (void **)&smb_buffer);
Jeff Laytonf1987b42008-11-15 11:12:47 -0500719 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 return rc;
Steve French133672e2007-11-13 22:41:37 +0000721
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400722 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)smb_buffer, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000724 cFYI(1, "Tree disconnect failed %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725
Steve French50c2f752007-07-13 00:33:32 +0000726 /* No need to return error on this operation if tid invalidated and
Jeff Laytonf1987b42008-11-15 11:12:47 -0500727 closed on server already e.g. due to tcp session crashing */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 if (rc == -EAGAIN)
729 rc = 0;
730
731 return rc;
732}
733
Jeff Layton766fdbb2011-01-11 07:24:21 -0500734/*
735 * This is a no-op for now. We're not really interested in the reply, but
736 * rather in the fact that the server sent one and that server->lstrp
737 * gets updated.
738 *
739 * FIXME: maybe we should consider checking that the reply matches request?
740 */
741static void
742cifs_echo_callback(struct mid_q_entry *mid)
743{
744 struct TCP_Server_Info *server = mid->callback_data;
745
746 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +0400747 add_credits(server, 1, CIFS_ECHO_OP);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500748}
749
750int
751CIFSSMBEcho(struct TCP_Server_Info *server)
752{
753 ECHO_REQ *smb;
754 int rc = 0;
Jeff Laytonfcc31cb2011-05-19 16:22:53 -0400755 struct kvec iov;
Jeff Layton766fdbb2011-01-11 07:24:21 -0500756
757 cFYI(1, "In echo request");
758
759 rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
760 if (rc)
761 return rc;
762
763 /* set up echo request */
Steve French5443d132011-03-13 05:08:25 +0000764 smb->hdr.Tid = 0xffff;
Jeff Layton99d86c82011-01-20 21:19:25 -0500765 smb->hdr.WordCount = 1;
766 put_unaligned_le16(1, &smb->EchoCount);
Jeff Layton820a8032011-05-04 08:05:26 -0400767 put_bcc(1, &smb->hdr);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500768 smb->Data[0] = 'a';
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000769 inc_rfc1001_len(smb, 3);
Jeff Laytonfcc31cb2011-05-19 16:22:53 -0400770 iov.iov_base = smb;
771 iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
Jeff Layton766fdbb2011-01-11 07:24:21 -0500772
Jeff Layton44d22d82011-10-19 15:29:49 -0400773 rc = cifs_call_async(server, &iov, 1, NULL, cifs_echo_callback,
Pavel Shilovskya891f0f2012-05-23 16:14:34 +0400774 server, CIFS_ASYNC_OP | CIFS_ECHO_OP);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500775 if (rc)
776 cFYI(1, "Echo request failed: %d", rc);
777
778 cifs_small_buf_release(smb);
779
780 return rc;
781}
782
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783int
Pavel Shilovsky58c45c52012-05-25 10:54:49 +0400784CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 LOGOFF_ANDX_REQ *pSMB;
787 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788
Joe Perchesb6b38f72010-04-21 03:50:45 +0000789 cFYI(1, "In SMBLogoff for session disconnect");
Jeff Layton14fbf502008-11-14 13:53:46 -0500790
791 /*
792 * BB: do we need to check validity of ses and server? They should
793 * always be valid since we have an active reference. If not, that
794 * should probably be a BUG()
795 */
796 if (!ses || !ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797 return -EIO;
798
Steve Frenchd7b619c2010-02-25 05:36:46 +0000799 mutex_lock(&ses->session_mutex);
Steve French3b795212008-11-13 19:45:32 +0000800 if (ses->need_reconnect)
801 goto session_already_dead; /* no need to send SMBlogoff if uid
802 already closed due to reconnect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
804 if (rc) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000805 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 return rc;
807 }
808
Pavel Shilovsky88257362012-05-23 14:01:59 +0400809 pSMB->hdr.Mid = get_next_mid(ses->server);
Steve French1982c342005-08-17 12:38:22 -0700810
Steve French96daf2b2011-05-27 04:34:02 +0000811 if (ses->server->sec_mode &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
813 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814
815 pSMB->hdr.Uid = ses->Suid;
816
817 pSMB->AndXCommand = 0xFF;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400818 rc = SendReceiveNoRsp(xid, ses, (char *) pSMB, 0);
Steve French3b795212008-11-13 19:45:32 +0000819session_already_dead:
Steve Frenchd7b619c2010-02-25 05:36:46 +0000820 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821
822 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000823 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 error */
825 if (rc == -EAGAIN)
826 rc = 0;
827 return rc;
828}
829
830int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400831CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
832 const char *fileName, __u16 type,
833 const struct nls_table *nls_codepage, int remap)
Steve French2d785a52007-07-15 01:48:57 +0000834{
835 TRANSACTION2_SPI_REQ *pSMB = NULL;
836 TRANSACTION2_SPI_RSP *pSMBr = NULL;
837 struct unlink_psx_rq *pRqD;
838 int name_len;
839 int rc = 0;
840 int bytes_returned = 0;
841 __u16 params, param_offset, offset, byte_count;
842
Joe Perchesb6b38f72010-04-21 03:50:45 +0000843 cFYI(1, "In POSIX delete");
Steve French2d785a52007-07-15 01:48:57 +0000844PsxDelete:
845 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
846 (void **) &pSMBr);
847 if (rc)
848 return rc;
849
850 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
851 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -0600852 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
853 PATH_MAX, nls_codepage, remap);
Steve French2d785a52007-07-15 01:48:57 +0000854 name_len++; /* trailing null */
855 name_len *= 2;
856 } else { /* BB add path length overrun check */
857 name_len = strnlen(fileName, PATH_MAX);
858 name_len++; /* trailing null */
859 strncpy(pSMB->FileName, fileName, name_len);
860 }
861
862 params = 6 + name_len;
863 pSMB->MaxParameterCount = cpu_to_le16(2);
864 pSMB->MaxDataCount = 0; /* BB double check this with jra */
865 pSMB->MaxSetupCount = 0;
866 pSMB->Reserved = 0;
867 pSMB->Flags = 0;
868 pSMB->Timeout = 0;
869 pSMB->Reserved2 = 0;
870 param_offset = offsetof(struct smb_com_transaction2_spi_req,
871 InformationLevel) - 4;
872 offset = param_offset + params;
873
874 /* Setup pointer to Request Data (inode type) */
875 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
876 pRqD->type = cpu_to_le16(type);
877 pSMB->ParameterOffset = cpu_to_le16(param_offset);
878 pSMB->DataOffset = cpu_to_le16(offset);
879 pSMB->SetupCount = 1;
880 pSMB->Reserved3 = 0;
881 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
882 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
883
884 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
885 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
886 pSMB->ParameterCount = cpu_to_le16(params);
887 pSMB->TotalParameterCount = pSMB->ParameterCount;
888 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
889 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000890 inc_rfc1001_len(pSMB, byte_count);
Steve French2d785a52007-07-15 01:48:57 +0000891 pSMB->ByteCount = cpu_to_le16(byte_count);
892 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
893 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000894 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000895 cFYI(1, "Posix delete returned %d", rc);
Steve French2d785a52007-07-15 01:48:57 +0000896 cifs_buf_release(pSMB);
897
898 cifs_stats_inc(&tcon->num_deletes);
899
900 if (rc == -EAGAIN)
901 goto PsxDelete;
902
903 return rc;
904}
905
906int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400907CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon,
908 const char *fileName, const struct nls_table *nls_codepage,
909 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910{
911 DELETE_FILE_REQ *pSMB = NULL;
912 DELETE_FILE_RSP *pSMBr = NULL;
913 int rc = 0;
914 int bytes_returned;
915 int name_len;
916
917DelFileRetry:
918 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
919 (void **) &pSMBr);
920 if (rc)
921 return rc;
922
923 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
924 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -0600925 cifsConvertToUTF16((__le16 *) pSMB->fileName, fileName,
926 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927 name_len++; /* trailing null */
928 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700929 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 name_len = strnlen(fileName, PATH_MAX);
931 name_len++; /* trailing null */
932 strncpy(pSMB->fileName, fileName, name_len);
933 }
934 pSMB->SearchAttributes =
935 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
936 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000937 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938 pSMB->ByteCount = cpu_to_le16(name_len + 1);
939 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
940 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700941 cifs_stats_inc(&tcon->num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000942 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000943 cFYI(1, "Error in RMFile = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944
945 cifs_buf_release(pSMB);
946 if (rc == -EAGAIN)
947 goto DelFileRetry;
948
949 return rc;
950}
951
952int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400953CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon,
954 const char *dirName, const struct nls_table *nls_codepage,
955 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956{
957 DELETE_DIRECTORY_REQ *pSMB = NULL;
958 DELETE_DIRECTORY_RSP *pSMBr = NULL;
959 int rc = 0;
960 int bytes_returned;
961 int name_len;
962
Joe Perchesb6b38f72010-04-21 03:50:45 +0000963 cFYI(1, "In CIFSSMBRmDir");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964RmDirRetry:
965 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
966 (void **) &pSMBr);
967 if (rc)
968 return rc;
969
970 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -0600971 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, dirName,
972 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973 name_len++; /* trailing null */
974 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700975 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 name_len = strnlen(dirName, PATH_MAX);
977 name_len++; /* trailing null */
978 strncpy(pSMB->DirName, dirName, name_len);
979 }
980
981 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000982 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 pSMB->ByteCount = cpu_to_le16(name_len + 1);
984 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
985 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700986 cifs_stats_inc(&tcon->num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000987 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000988 cFYI(1, "Error in RMDir = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989
990 cifs_buf_release(pSMB);
991 if (rc == -EAGAIN)
992 goto RmDirRetry;
993 return rc;
994}
995
996int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400997CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon,
Steve French737b7582005-04-28 22:41:06 -0700998 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999{
1000 int rc = 0;
1001 CREATE_DIRECTORY_REQ *pSMB = NULL;
1002 CREATE_DIRECTORY_RSP *pSMBr = NULL;
1003 int bytes_returned;
1004 int name_len;
1005
Joe Perchesb6b38f72010-04-21 03:50:45 +00001006 cFYI(1, "In CIFSSMBMkDir");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007MkDirRetry:
1008 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
1009 (void **) &pSMBr);
1010 if (rc)
1011 return rc;
1012
1013 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06001014 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
1015 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016 name_len++; /* trailing null */
1017 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -07001018 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019 name_len = strnlen(name, PATH_MAX);
1020 name_len++; /* trailing null */
1021 strncpy(pSMB->DirName, name, name_len);
1022 }
1023
1024 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001025 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026 pSMB->ByteCount = cpu_to_le16(name_len + 1);
1027 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1028 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001029 cifs_stats_inc(&tcon->num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +00001030 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001031 cFYI(1, "Error in Mkdir = %d", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07001032
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033 cifs_buf_release(pSMB);
1034 if (rc == -EAGAIN)
1035 goto MkDirRetry;
1036 return rc;
1037}
1038
Steve French2dd29d32007-04-23 22:07:35 +00001039int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001040CIFSPOSIXCreate(const unsigned int xid, struct cifs_tcon *tcon,
1041 __u32 posix_flags, __u64 mode, __u16 *netfid,
1042 FILE_UNIX_BASIC_INFO *pRetData, __u32 *pOplock,
1043 const char *name, const struct nls_table *nls_codepage,
1044 int remap)
Steve French2dd29d32007-04-23 22:07:35 +00001045{
1046 TRANSACTION2_SPI_REQ *pSMB = NULL;
1047 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1048 int name_len;
1049 int rc = 0;
1050 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001051 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +00001052 OPEN_PSX_REQ *pdata;
1053 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +00001054
Joe Perchesb6b38f72010-04-21 03:50:45 +00001055 cFYI(1, "In POSIX Create");
Steve French2dd29d32007-04-23 22:07:35 +00001056PsxCreat:
1057 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1058 (void **) &pSMBr);
1059 if (rc)
1060 return rc;
1061
1062 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1063 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001064 cifsConvertToUTF16((__le16 *) pSMB->FileName, name,
1065 PATH_MAX, nls_codepage, remap);
Steve French2dd29d32007-04-23 22:07:35 +00001066 name_len++; /* trailing null */
1067 name_len *= 2;
1068 } else { /* BB improve the check for buffer overruns BB */
1069 name_len = strnlen(name, PATH_MAX);
1070 name_len++; /* trailing null */
1071 strncpy(pSMB->FileName, name, name_len);
1072 }
1073
1074 params = 6 + name_len;
1075 count = sizeof(OPEN_PSX_REQ);
1076 pSMB->MaxParameterCount = cpu_to_le16(2);
1077 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1078 pSMB->MaxSetupCount = 0;
1079 pSMB->Reserved = 0;
1080 pSMB->Flags = 0;
1081 pSMB->Timeout = 0;
1082 pSMB->Reserved2 = 0;
1083 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001084 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001085 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001086 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001087 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001088 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001089 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001090 pdata->OpenFlags = cpu_to_le32(*pOplock);
1091 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1092 pSMB->DataOffset = cpu_to_le16(offset);
1093 pSMB->SetupCount = 1;
1094 pSMB->Reserved3 = 0;
1095 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1096 byte_count = 3 /* pad */ + params + count;
1097
1098 pSMB->DataCount = cpu_to_le16(count);
1099 pSMB->ParameterCount = cpu_to_le16(params);
1100 pSMB->TotalDataCount = pSMB->DataCount;
1101 pSMB->TotalParameterCount = pSMB->ParameterCount;
1102 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1103 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001104 inc_rfc1001_len(pSMB, byte_count);
Steve French2dd29d32007-04-23 22:07:35 +00001105 pSMB->ByteCount = cpu_to_le16(byte_count);
1106 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1107 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1108 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001109 cFYI(1, "Posix create returned %d", rc);
Steve French2dd29d32007-04-23 22:07:35 +00001110 goto psx_create_err;
1111 }
1112
Joe Perchesb6b38f72010-04-21 03:50:45 +00001113 cFYI(1, "copying inode info");
Steve French2dd29d32007-04-23 22:07:35 +00001114 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1115
Jeff Layton820a8032011-05-04 08:05:26 -04001116 if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) {
Steve French2dd29d32007-04-23 22:07:35 +00001117 rc = -EIO; /* bad smb */
1118 goto psx_create_err;
1119 }
1120
1121 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001122 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001123 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001124
Steve French2dd29d32007-04-23 22:07:35 +00001125 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001126 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001127 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1128 /* Let caller know file was created so we can set the mode. */
1129 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001130 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001131 *pOplock |= CIFS_CREATE_ACTION;
1132 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001133 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1134 pRetData->Type = cpu_to_le32(-1); /* unknown */
Joe Perchesb6b38f72010-04-21 03:50:45 +00001135 cFYI(DBG2, "unknown type");
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001136 } else {
Jeff Layton820a8032011-05-04 08:05:26 -04001137 if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001138 + sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001139 cERROR(1, "Open response data too small");
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001140 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001141 goto psx_create_err;
1142 }
Steve French50c2f752007-07-13 00:33:32 +00001143 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001144 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001145 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001146 }
Steve French2dd29d32007-04-23 22:07:35 +00001147
1148psx_create_err:
1149 cifs_buf_release(pSMB);
1150
Steve French65bc98b2009-07-10 15:27:25 +00001151 if (posix_flags & SMB_O_DIRECTORY)
1152 cifs_stats_inc(&tcon->num_posixmkdirs);
1153 else
1154 cifs_stats_inc(&tcon->num_posixopens);
Steve French2dd29d32007-04-23 22:07:35 +00001155
1156 if (rc == -EAGAIN)
1157 goto PsxCreat;
1158
Steve French50c2f752007-07-13 00:33:32 +00001159 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001160}
1161
Steve Frencha9d02ad2005-08-24 23:06:05 -07001162static __u16 convert_disposition(int disposition)
1163{
1164 __u16 ofun = 0;
1165
1166 switch (disposition) {
1167 case FILE_SUPERSEDE:
1168 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1169 break;
1170 case FILE_OPEN:
1171 ofun = SMBOPEN_OAPPEND;
1172 break;
1173 case FILE_CREATE:
1174 ofun = SMBOPEN_OCREATE;
1175 break;
1176 case FILE_OPEN_IF:
1177 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1178 break;
1179 case FILE_OVERWRITE:
1180 ofun = SMBOPEN_OTRUNC;
1181 break;
1182 case FILE_OVERWRITE_IF:
1183 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1184 break;
1185 default:
Joe Perchesb6b38f72010-04-21 03:50:45 +00001186 cFYI(1, "unknown disposition %d", disposition);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001187 ofun = SMBOPEN_OAPPEND; /* regular open */
1188 }
1189 return ofun;
1190}
1191
Jeff Layton35fc37d2008-05-14 10:22:03 -07001192static int
1193access_flags_to_smbopen_mode(const int access_flags)
1194{
1195 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1196
1197 if (masked_flags == GENERIC_READ)
1198 return SMBOPEN_READ;
1199 else if (masked_flags == GENERIC_WRITE)
1200 return SMBOPEN_WRITE;
1201
1202 /* just go for read/write */
1203 return SMBOPEN_READWRITE;
1204}
1205
Steve Frencha9d02ad2005-08-24 23:06:05 -07001206int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001207SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001208 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001209 const int access_flags, const int create_options, __u16 *netfid,
1210 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001211 const struct nls_table *nls_codepage, int remap)
1212{
1213 int rc = -EACCES;
1214 OPENX_REQ *pSMB = NULL;
1215 OPENX_RSP *pSMBr = NULL;
1216 int bytes_returned;
1217 int name_len;
1218 __u16 count;
1219
1220OldOpenRetry:
1221 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1222 (void **) &pSMBr);
1223 if (rc)
1224 return rc;
1225
1226 pSMB->AndXCommand = 0xFF; /* none */
1227
1228 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1229 count = 1; /* account for one byte pad to word boundary */
1230 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001231 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1232 fileName, PATH_MAX, nls_codepage, remap);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001233 name_len++; /* trailing null */
1234 name_len *= 2;
1235 } else { /* BB improve check for buffer overruns BB */
1236 count = 0; /* no pad */
1237 name_len = strnlen(fileName, PATH_MAX);
1238 name_len++; /* trailing null */
1239 strncpy(pSMB->fileName, fileName, name_len);
1240 }
1241 if (*pOplock & REQ_OPLOCK)
1242 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001243 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001244 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001245
Steve Frencha9d02ad2005-08-24 23:06:05 -07001246 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001247 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001248 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1249 /* set file as system file if special file such
1250 as fifo and server expecting SFU style and
1251 no Unix extensions */
1252
Steve French790fe572007-07-07 19:25:05 +00001253 if (create_options & CREATE_OPTION_SPECIAL)
1254 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001255 else /* BB FIXME BB */
1256 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001257
Jeff Layton67750fb2008-05-09 22:28:02 +00001258 if (create_options & CREATE_OPTION_READONLY)
1259 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001260
1261 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001262/* pSMB->CreateOptions = cpu_to_le32(create_options &
1263 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001264 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001265
1266 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001267 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001268 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001269 inc_rfc1001_len(pSMB, count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001270
1271 pSMB->ByteCount = cpu_to_le16(count);
1272 /* long_op set to 1 to allow for oplock break timeouts */
1273 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001274 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001275 cifs_stats_inc(&tcon->num_opens);
1276 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001277 cFYI(1, "Error in Open = %d", rc);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001278 } else {
1279 /* BB verify if wct == 15 */
1280
Steve French582d21e2008-05-13 04:54:12 +00001281/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001282
1283 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1284 /* Let caller know file was created so we can set the mode. */
1285 /* Do we care about the CreateAction in any other cases? */
1286 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001287/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001288 *pOplock |= CIFS_CREATE_ACTION; */
1289 /* BB FIXME END */
1290
Steve French790fe572007-07-07 19:25:05 +00001291 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001292 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1293 pfile_info->LastAccessTime = 0; /* BB fixme */
1294 pfile_info->LastWriteTime = 0; /* BB fixme */
1295 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001296 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001297 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001298 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001299 pfile_info->AllocationSize =
1300 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1301 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001302 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001303 pfile_info->DeletePending = 0;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001304 }
1305 }
1306
1307 cifs_buf_release(pSMB);
1308 if (rc == -EAGAIN)
1309 goto OldOpenRetry;
1310 return rc;
1311}
1312
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001314CIFSSMBOpen(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001316 const int access_flags, const int create_options, __u16 *netfid,
1317 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001318 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319{
1320 int rc = -EACCES;
1321 OPEN_REQ *pSMB = NULL;
1322 OPEN_RSP *pSMBr = NULL;
1323 int bytes_returned;
1324 int name_len;
1325 __u16 count;
1326
1327openRetry:
1328 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1329 (void **) &pSMBr);
1330 if (rc)
1331 return rc;
1332
1333 pSMB->AndXCommand = 0xFF; /* none */
1334
1335 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1336 count = 1; /* account for one byte pad to word boundary */
1337 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001338 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1339 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340 name_len++; /* trailing null */
1341 name_len *= 2;
1342 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001343 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344 count = 0; /* no pad */
1345 name_len = strnlen(fileName, PATH_MAX);
1346 name_len++; /* trailing null */
1347 pSMB->NameLength = cpu_to_le16(name_len);
1348 strncpy(pSMB->fileName, fileName, name_len);
1349 }
1350 if (*pOplock & REQ_OPLOCK)
1351 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001352 else if (*pOplock & REQ_BATCHOPLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1355 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -07001356 /* set file as system file if special file such
1357 as fifo and server expecting SFU style and
1358 no Unix extensions */
Steve French790fe572007-07-07 19:25:05 +00001359 if (create_options & CREATE_OPTION_SPECIAL)
Steve Frencheda3c0292005-07-21 15:20:28 -07001360 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1361 else
1362 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Jeff Layton67750fb2008-05-09 22:28:02 +00001363
Linus Torvalds1da177e2005-04-16 15:20:36 -07001364 /* XP does not handle ATTR_POSIX_SEMANTICS */
1365 /* but it helps speed up case sensitive checks for other
1366 servers such as Samba */
1367 if (tcon->ses->capabilities & CAP_UNIX)
1368 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1369
Jeff Layton67750fb2008-05-09 22:28:02 +00001370 if (create_options & CREATE_OPTION_READONLY)
1371 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1372
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1374 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -07001375 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001376 /* BB Expirement with various impersonation levels and verify */
1377 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378 pSMB->SecurityFlags =
1379 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1380
1381 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001382 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383
1384 pSMB->ByteCount = cpu_to_le16(count);
1385 /* long_op set to 1 to allow for oplock break timeouts */
1386 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001387 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001388 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001390 cFYI(1, "Error in Open = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391 } else {
Steve French09d1db52005-04-28 22:41:08 -07001392 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1394 /* Let caller know file was created so we can set the mode. */
1395 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001396 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve French50c2f752007-07-13 00:33:32 +00001397 *pOplock |= CIFS_CREATE_ACTION;
Steve French790fe572007-07-07 19:25:05 +00001398 if (pfile_info) {
Steve French61e74802008-12-03 00:57:54 +00001399 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1400 36 /* CreationTime to Attributes */);
1401 /* the file_info buf is endian converted by caller */
1402 pfile_info->AllocationSize = pSMBr->AllocationSize;
1403 pfile_info->EndOfFile = pSMBr->EndOfFile;
1404 pfile_info->NumberOfLinks = cpu_to_le32(1);
1405 pfile_info->DeletePending = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001408
Linus Torvalds1da177e2005-04-16 15:20:36 -07001409 cifs_buf_release(pSMB);
1410 if (rc == -EAGAIN)
1411 goto openRetry;
1412 return rc;
1413}
1414
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001415/*
1416 * Discard any remaining data in the current SMB. To do this, we borrow the
1417 * current bigbuf.
1418 */
1419static int
1420cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1421{
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001422 unsigned int rfclen = get_rfc1002_length(server->smallbuf);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001423 int remaining = rfclen + 4 - server->total_read;
1424 struct cifs_readdata *rdata = mid->callback_data;
1425
1426 while (remaining > 0) {
1427 int length;
1428
1429 length = cifs_read_from_socket(server, server->bigbuf,
1430 min_t(unsigned int, remaining,
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001431 CIFSMaxBufSize + MAX_HEADER_SIZE(server)));
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001432 if (length < 0)
1433 return length;
1434 server->total_read += length;
1435 remaining -= length;
1436 }
1437
1438 dequeue_mid(mid, rdata->result);
1439 return 0;
1440}
1441
1442static int
1443cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1444{
1445 int length, len;
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001446 unsigned int data_offset, data_len;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001447 struct cifs_readdata *rdata = mid->callback_data;
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001448 char *buf = server->smallbuf;
1449 unsigned int buflen = get_rfc1002_length(buf) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001450
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001451 cFYI(1, "%s: mid=%llu offset=%llu bytes=%u", __func__,
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001452 mid->mid, rdata->offset, rdata->bytes);
1453
1454 /*
1455 * read the rest of READ_RSP header (sans Data array), or whatever we
1456 * can if there's not enough data. At this point, we've read down to
1457 * the Mid.
1458 */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001459 len = min_t(unsigned int, buflen, server->vals->read_rsp_size) -
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001460 HEADER_SIZE(server) + 1;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001461
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001462 rdata->iov[0].iov_base = buf + HEADER_SIZE(server) - 1;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001463 rdata->iov[0].iov_len = len;
1464
1465 length = cifs_readv_from_socket(server, rdata->iov, 1, len);
1466 if (length < 0)
1467 return length;
1468 server->total_read += length;
1469
1470 /* Was the SMB read successful? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001471 rdata->result = server->ops->map_error(buf, false);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001472 if (rdata->result != 0) {
1473 cFYI(1, "%s: server returned error %d", __func__,
1474 rdata->result);
1475 return cifs_readv_discard(server, mid);
1476 }
1477
1478 /* Is there enough to get to the rest of the READ_RSP header? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001479 if (server->total_read < server->vals->read_rsp_size) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001480 cFYI(1, "%s: server returned short header. got=%u expected=%zu",
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001481 __func__, server->total_read,
1482 server->vals->read_rsp_size);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001483 rdata->result = -EIO;
1484 return cifs_readv_discard(server, mid);
1485 }
1486
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001487 data_offset = server->ops->read_data_offset(buf) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001488 if (data_offset < server->total_read) {
1489 /*
1490 * win2k8 sometimes sends an offset of 0 when the read
1491 * is beyond the EOF. Treat it as if the data starts just after
1492 * the header.
1493 */
1494 cFYI(1, "%s: data offset (%u) inside read response header",
1495 __func__, data_offset);
1496 data_offset = server->total_read;
1497 } else if (data_offset > MAX_CIFS_SMALL_BUFFER_SIZE) {
1498 /* data_offset is beyond the end of smallbuf */
1499 cFYI(1, "%s: data offset (%u) beyond end of smallbuf",
1500 __func__, data_offset);
1501 rdata->result = -EIO;
1502 return cifs_readv_discard(server, mid);
1503 }
1504
1505 cFYI(1, "%s: total_read=%u data_offset=%u", __func__,
1506 server->total_read, data_offset);
1507
1508 len = data_offset - server->total_read;
1509 if (len > 0) {
1510 /* read any junk before data into the rest of smallbuf */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001511 rdata->iov[0].iov_base = buf + server->total_read;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001512 rdata->iov[0].iov_len = len;
1513 length = cifs_readv_from_socket(server, rdata->iov, 1, len);
1514 if (length < 0)
1515 return length;
1516 server->total_read += length;
1517 }
1518
1519 /* set up first iov for signature check */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001520 rdata->iov[0].iov_base = buf;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001521 rdata->iov[0].iov_len = server->total_read;
1522 cFYI(1, "0: iov_base=%p iov_len=%zu",
1523 rdata->iov[0].iov_base, rdata->iov[0].iov_len);
1524
1525 /* how much data is in the response? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001526 data_len = server->ops->read_data_length(buf);
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001527 if (data_offset + data_len > buflen) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001528 /* data_len is corrupt -- discard frame */
1529 rdata->result = -EIO;
1530 return cifs_readv_discard(server, mid);
1531 }
1532
1533 /* marshal up the page array */
Jeff Layton3cf003c2012-07-11 09:09:36 -04001534 cifs_kmap_lock();
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001535 len = rdata->marshal_iov(rdata, data_len);
Jeff Layton3cf003c2012-07-11 09:09:36 -04001536 cifs_kmap_unlock();
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001537 data_len -= len;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001538
1539 /* issue the read if we have any iovecs left to fill */
1540 if (rdata->nr_iov > 1) {
1541 length = cifs_readv_from_socket(server, &rdata->iov[1],
1542 rdata->nr_iov - 1, len);
1543 if (length < 0)
1544 return length;
1545 server->total_read += length;
1546 } else {
1547 length = 0;
1548 }
1549
1550 rdata->bytes = length;
1551
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001552 cFYI(1, "total_read=%u buflen=%u remaining=%u", server->total_read,
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001553 buflen, data_len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001554
1555 /* discard anything left over */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001556 if (server->total_read < buflen)
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001557 return cifs_readv_discard(server, mid);
1558
1559 dequeue_mid(mid, false);
1560 return length;
1561}
1562
1563static void
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001564cifs_readv_callback(struct mid_q_entry *mid)
1565{
1566 struct cifs_readdata *rdata = mid->callback_data;
1567 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1568 struct TCP_Server_Info *server = tcon->ses->server;
1569
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001570 cFYI(1, "%s: mid=%llu state=%d result=%d bytes=%u", __func__,
1571 mid->mid, mid->mid_state, rdata->result, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001572
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001573 switch (mid->mid_state) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001574 case MID_RESPONSE_RECEIVED:
1575 /* result already set, check signature */
1576 if (server->sec_mode &
1577 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
1578 if (cifs_verify_signature(rdata->iov, rdata->nr_iov,
1579 server, mid->sequence_number + 1))
1580 cERROR(1, "Unexpected SMB signature");
1581 }
1582 /* FIXME: should this be counted toward the initiating task? */
1583 task_io_account_read(rdata->bytes);
1584 cifs_stats_bytes_read(tcon, rdata->bytes);
1585 break;
1586 case MID_REQUEST_SUBMITTED:
1587 case MID_RETRY_NEEDED:
1588 rdata->result = -EAGAIN;
1589 break;
1590 default:
1591 rdata->result = -EIO;
1592 }
1593
Jeff Laytonda472fc2012-03-23 14:40:53 -04001594 queue_work(cifsiod_wq, &rdata->work);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001595 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04001596 add_credits(server, 1, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001597}
1598
1599/* cifs_async_readv - send an async write, and set up mid to handle result */
1600int
1601cifs_async_readv(struct cifs_readdata *rdata)
1602{
1603 int rc;
1604 READ_REQ *smb = NULL;
1605 int wct;
1606 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1607
1608 cFYI(1, "%s: offset=%llu bytes=%u", __func__,
1609 rdata->offset, rdata->bytes);
1610
1611 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1612 wct = 12;
1613 else {
1614 wct = 10; /* old style read */
1615 if ((rdata->offset >> 32) > 0) {
1616 /* can not handle this big offset for old */
1617 return -EIO;
1618 }
1619 }
1620
1621 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **)&smb);
1622 if (rc)
1623 return rc;
1624
1625 smb->hdr.Pid = cpu_to_le16((__u16)rdata->pid);
1626 smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16));
1627
1628 smb->AndXCommand = 0xFF; /* none */
1629 smb->Fid = rdata->cfile->netfid;
1630 smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF);
1631 if (wct == 12)
1632 smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32);
1633 smb->Remaining = 0;
1634 smb->MaxCount = cpu_to_le16(rdata->bytes & 0xFFFF);
1635 smb->MaxCountHigh = cpu_to_le32(rdata->bytes >> 16);
1636 if (wct == 12)
1637 smb->ByteCount = 0;
1638 else {
1639 /* old style read */
1640 struct smb_com_readx_req *smbr =
1641 (struct smb_com_readx_req *)smb;
1642 smbr->ByteCount = 0;
1643 }
1644
1645 /* 4 for RFC1001 length + 1 for BCC */
1646 rdata->iov[0].iov_base = smb;
1647 rdata->iov[0].iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
1648
Jeff Layton6993f742012-05-16 07:13:17 -04001649 kref_get(&rdata->refcount);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001650 rc = cifs_call_async(tcon->ses->server, rdata->iov, 1,
1651 cifs_readv_receive, cifs_readv_callback,
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04001652 rdata, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001653
1654 if (rc == 0)
1655 cifs_stats_inc(&tcon->num_reads);
Jeff Layton6993f742012-05-16 07:13:17 -04001656 else
1657 kref_put(&rdata->refcount, cifs_readdata_release);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001658
1659 cifs_small_buf_release(smb);
1660 return rc;
1661}
1662
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001664CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
1665 unsigned int *nbytes, char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001666{
1667 int rc = -EACCES;
1668 READ_REQ *pSMB = NULL;
1669 READ_RSP *pSMBr = NULL;
1670 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001671 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001672 int resp_buf_type = 0;
1673 struct kvec iov[1];
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001674 __u32 pid = io_parms->pid;
1675 __u16 netfid = io_parms->netfid;
1676 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001677 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001678 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679
Joe Perchesb6b38f72010-04-21 03:50:45 +00001680 cFYI(1, "Reading %d bytes on fid %d", count, netfid);
Steve French790fe572007-07-07 19:25:05 +00001681 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001682 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001683 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001684 wct = 10; /* old style read */
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001685 if ((offset >> 32) > 0) {
Steve French4c3130e2008-12-09 00:28:16 +00001686 /* can not handle this big offset for old */
1687 return -EIO;
1688 }
1689 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690
1691 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001692 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693 if (rc)
1694 return rc;
1695
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001696 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1697 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1698
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699 /* tcon and ses pointer are checked in smb_init */
1700 if (tcon->ses->server == NULL)
1701 return -ECONNABORTED;
1702
Steve Frenchec637e32005-12-12 20:53:18 -08001703 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704 pSMB->Fid = netfid;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001705 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001706 if (wct == 12)
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001707 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001708
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709 pSMB->Remaining = 0;
1710 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1711 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001712 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001713 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1714 else {
1715 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001716 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001717 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001718 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001719 }
Steve Frenchec637e32005-12-12 20:53:18 -08001720
1721 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001722 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve Frencha761ac52007-10-18 21:45:27 +00001723 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Jeff Layton77499812011-01-11 07:24:23 -05001724 &resp_buf_type, CIFS_LOG_ERROR);
Steve Frencha4544342005-08-24 13:59:35 -07001725 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001726 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001728 cERROR(1, "Send error in read = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729 } else {
1730 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1731 data_length = data_length << 16;
1732 data_length += le16_to_cpu(pSMBr->DataLength);
1733 *nbytes = data_length;
1734
1735 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001736 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737 || (data_length > count)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001738 cFYI(1, "bad length %d for count %d",
1739 data_length, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740 rc = -EIO;
1741 *nbytes = 0;
1742 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001743 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001744 le16_to_cpu(pSMBr->DataOffset);
1745/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001746 cERROR(1, "Faulting on read rc = %d",rc);
Steve French50c2f752007-07-13 00:33:32 +00001747 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001748 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001749 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001750 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751 }
1752 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753
Steve French4b8f9302006-02-26 16:41:18 +00001754/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001755 if (*buf) {
1756 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001757 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001758 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001759 cifs_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001760 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001761 /* return buffer to caller to free */
1762 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001763 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001764 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001765 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001766 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001767 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001768
1769 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001770 since file handle passed in no longer valid */
1771 return rc;
1772}
1773
Steve Frenchec637e32005-12-12 20:53:18 -08001774
Linus Torvalds1da177e2005-04-16 15:20:36 -07001775int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001776CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001777 unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001778 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001779{
1780 int rc = -EACCES;
1781 WRITE_REQ *pSMB = NULL;
1782 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001783 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001784 __u32 bytes_sent;
1785 __u16 byte_count;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001786 __u32 pid = io_parms->pid;
1787 __u16 netfid = io_parms->netfid;
1788 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001789 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001790 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001791
Steve Frencha24e2d72010-04-03 17:20:21 +00001792 *nbytes = 0;
1793
Joe Perchesb6b38f72010-04-21 03:50:45 +00001794 /* cFYI(1, "write at %lld %d bytes", offset, count);*/
Steve French790fe572007-07-07 19:25:05 +00001795 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001796 return -ECONNABORTED;
1797
Steve French790fe572007-07-07 19:25:05 +00001798 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001799 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001800 else {
Steve French1c955182005-08-30 20:58:07 -07001801 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001802 if ((offset >> 32) > 0) {
1803 /* can not handle big offset for old srv */
1804 return -EIO;
1805 }
1806 }
Steve French1c955182005-08-30 20:58:07 -07001807
1808 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001809 (void **) &pSMBr);
1810 if (rc)
1811 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001812
1813 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1814 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1815
Linus Torvalds1da177e2005-04-16 15:20:36 -07001816 /* tcon and ses pointer are checked in smb_init */
1817 if (tcon->ses->server == NULL)
1818 return -ECONNABORTED;
1819
1820 pSMB->AndXCommand = 0xFF; /* none */
1821 pSMB->Fid = netfid;
1822 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001823 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001824 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001825
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826 pSMB->Reserved = 0xFFFFFFFF;
1827 pSMB->WriteMode = 0;
1828 pSMB->Remaining = 0;
1829
Steve French50c2f752007-07-13 00:33:32 +00001830 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001831 can send more if LARGE_WRITE_X capability returned by the server and if
1832 our buffer is big enough or if we convert to iovecs on socket writes
1833 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001834 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001835 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1836 } else {
1837 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1838 & ~0xFF;
1839 }
1840
1841 if (bytes_sent > count)
1842 bytes_sent = count;
1843 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001844 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001845 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001846 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001847 else if (ubuf) {
1848 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849 cifs_buf_release(pSMB);
1850 return -EFAULT;
1851 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001852 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853 /* No buffer */
1854 cifs_buf_release(pSMB);
1855 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001856 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001857 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001858 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001859 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001860 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001861
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1863 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001864 inc_rfc1001_len(pSMB, byte_count);
Steve French1c955182005-08-30 20:58:07 -07001865
Steve French790fe572007-07-07 19:25:05 +00001866 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001867 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001868 else { /* old style write has byte count 4 bytes earlier
1869 so 4 bytes pad */
1870 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001871 (struct smb_com_writex_req *)pSMB;
1872 pSMBW->ByteCount = cpu_to_le16(byte_count);
1873 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874
1875 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1876 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001877 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001878 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00001879 cFYI(1, "Send error in write = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001880 } else {
1881 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1882 *nbytes = (*nbytes) << 16;
1883 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301884
1885 /*
1886 * Mask off high 16 bits when bytes written as returned by the
1887 * server is greater than bytes requested by the client. Some
1888 * OS/2 servers are known to set incorrect CountHigh values.
1889 */
1890 if (*nbytes > count)
1891 *nbytes &= 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001892 }
1893
1894 cifs_buf_release(pSMB);
1895
Steve French50c2f752007-07-13 00:33:32 +00001896 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897 since file handle passed in no longer valid */
1898
1899 return rc;
1900}
1901
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001902void
1903cifs_writedata_release(struct kref *refcount)
1904{
1905 struct cifs_writedata *wdata = container_of(refcount,
1906 struct cifs_writedata, refcount);
1907
1908 if (wdata->cfile)
1909 cifsFileInfo_put(wdata->cfile);
1910
1911 kfree(wdata);
1912}
1913
1914/*
1915 * Write failed with a retryable error. Resend the write request. It's also
1916 * possible that the page was redirtied so re-clean the page.
1917 */
1918static void
1919cifs_writev_requeue(struct cifs_writedata *wdata)
1920{
1921 int i, rc;
1922 struct inode *inode = wdata->cfile->dentry->d_inode;
1923
1924 for (i = 0; i < wdata->nr_pages; i++) {
1925 lock_page(wdata->pages[i]);
1926 clear_page_dirty_for_io(wdata->pages[i]);
1927 }
1928
1929 do {
1930 rc = cifs_async_writev(wdata);
1931 } while (rc == -EAGAIN);
1932
1933 for (i = 0; i < wdata->nr_pages; i++) {
1934 if (rc != 0)
1935 SetPageError(wdata->pages[i]);
1936 unlock_page(wdata->pages[i]);
1937 }
1938
1939 mapping_set_error(inode->i_mapping, rc);
1940 kref_put(&wdata->refcount, cifs_writedata_release);
1941}
1942
Jeff Laytonc2e87642012-03-23 14:40:55 -04001943void
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001944cifs_writev_complete(struct work_struct *work)
1945{
1946 struct cifs_writedata *wdata = container_of(work,
1947 struct cifs_writedata, work);
1948 struct inode *inode = wdata->cfile->dentry->d_inode;
1949 int i = 0;
1950
1951 if (wdata->result == 0) {
Jeff Layton597b0272012-03-23 14:40:56 -04001952 spin_lock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001953 cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
Jeff Layton597b0272012-03-23 14:40:56 -04001954 spin_unlock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001955 cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
1956 wdata->bytes);
1957 } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
1958 return cifs_writev_requeue(wdata);
1959
1960 for (i = 0; i < wdata->nr_pages; i++) {
1961 struct page *page = wdata->pages[i];
1962 if (wdata->result == -EAGAIN)
1963 __set_page_dirty_nobuffers(page);
1964 else if (wdata->result < 0)
1965 SetPageError(page);
1966 end_page_writeback(page);
1967 page_cache_release(page);
1968 }
1969 if (wdata->result != -EAGAIN)
1970 mapping_set_error(inode->i_mapping, wdata->result);
1971 kref_put(&wdata->refcount, cifs_writedata_release);
1972}
1973
1974struct cifs_writedata *
Jeff Laytonc2e87642012-03-23 14:40:55 -04001975cifs_writedata_alloc(unsigned int nr_pages, work_func_t complete)
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001976{
1977 struct cifs_writedata *wdata;
1978
1979 /* this would overflow */
1980 if (nr_pages == 0) {
1981 cERROR(1, "%s: called with nr_pages == 0!", __func__);
1982 return NULL;
1983 }
1984
1985 /* writedata + number of page pointers */
1986 wdata = kzalloc(sizeof(*wdata) +
1987 sizeof(struct page *) * (nr_pages - 1), GFP_NOFS);
1988 if (wdata != NULL) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001989 kref_init(&wdata->refcount);
Jeff Laytonda82f7e2012-03-23 14:40:56 -04001990 INIT_LIST_HEAD(&wdata->list);
1991 init_completion(&wdata->done);
1992 INIT_WORK(&wdata->work, complete);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001993 }
1994 return wdata;
1995}
1996
1997/*
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001998 * Check the mid_state and signature on received buffer (if any), and queue the
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001999 * workqueue completion task.
2000 */
2001static void
2002cifs_writev_callback(struct mid_q_entry *mid)
2003{
2004 struct cifs_writedata *wdata = mid->callback_data;
Steve French96daf2b2011-05-27 04:34:02 +00002005 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002006 unsigned int written;
2007 WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
2008
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04002009 switch (mid->mid_state) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002010 case MID_RESPONSE_RECEIVED:
2011 wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
2012 if (wdata->result != 0)
2013 break;
2014
2015 written = le16_to_cpu(smb->CountHigh);
2016 written <<= 16;
2017 written += le16_to_cpu(smb->Count);
2018 /*
2019 * Mask off high 16 bits when bytes written as returned
2020 * by the server is greater than bytes requested by the
2021 * client. OS/2 servers are known to set incorrect
2022 * CountHigh values.
2023 */
2024 if (written > wdata->bytes)
2025 written &= 0xFFFF;
2026
2027 if (written < wdata->bytes)
2028 wdata->result = -ENOSPC;
2029 else
2030 wdata->bytes = written;
2031 break;
2032 case MID_REQUEST_SUBMITTED:
2033 case MID_RETRY_NEEDED:
2034 wdata->result = -EAGAIN;
2035 break;
2036 default:
2037 wdata->result = -EIO;
2038 break;
2039 }
2040
Jeff Laytonda472fc2012-03-23 14:40:53 -04002041 queue_work(cifsiod_wq, &wdata->work);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002042 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002043 add_credits(tcon->ses->server, 1, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002044}
2045
2046/* cifs_async_writev - send an async write, and set up mid to handle result */
2047int
2048cifs_async_writev(struct cifs_writedata *wdata)
2049{
2050 int i, rc = -EACCES;
2051 WRITE_REQ *smb = NULL;
2052 int wct;
Steve French96daf2b2011-05-27 04:34:02 +00002053 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002054 struct kvec *iov = NULL;
2055
2056 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
2057 wct = 14;
2058 } else {
2059 wct = 12;
2060 if (wdata->offset >> 32 > 0) {
2061 /* can not handle big offset for old srv */
2062 return -EIO;
2063 }
2064 }
2065
2066 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
2067 if (rc)
2068 goto async_writev_out;
2069
2070 /* 1 iov per page + 1 for header */
2071 iov = kzalloc((wdata->nr_pages + 1) * sizeof(*iov), GFP_NOFS);
2072 if (iov == NULL) {
2073 rc = -ENOMEM;
2074 goto async_writev_out;
2075 }
2076
Jeff Laytonfe5f5d22012-03-23 14:40:55 -04002077 smb->hdr.Pid = cpu_to_le16((__u16)wdata->pid);
2078 smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16));
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002079
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002080 smb->AndXCommand = 0xFF; /* none */
2081 smb->Fid = wdata->cfile->netfid;
2082 smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
2083 if (wct == 14)
2084 smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
2085 smb->Reserved = 0xFFFFFFFF;
2086 smb->WriteMode = 0;
2087 smb->Remaining = 0;
2088
2089 smb->DataOffset =
2090 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
2091
2092 /* 4 for RFC1001 length + 1 for BCC */
2093 iov[0].iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4 + 1;
2094 iov[0].iov_base = smb;
2095
Jeff Laytone9492872012-03-23 14:40:56 -04002096 /*
2097 * This function should marshal up the page array into the kvec
2098 * array, reserving [0] for the header. It should kmap the pages
2099 * and set the iov_len properly for each one. It may also set
2100 * wdata->bytes too.
2101 */
Jeff Layton3cf003c2012-07-11 09:09:36 -04002102 cifs_kmap_lock();
Jeff Laytone9492872012-03-23 14:40:56 -04002103 wdata->marshal_iov(iov, wdata);
Jeff Layton3cf003c2012-07-11 09:09:36 -04002104 cifs_kmap_unlock();
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002105
2106 cFYI(1, "async write at %llu %u bytes", wdata->offset, wdata->bytes);
2107
2108 smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
2109 smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16);
2110
2111 if (wct == 14) {
2112 inc_rfc1001_len(&smb->hdr, wdata->bytes + 1);
2113 put_bcc(wdata->bytes + 1, &smb->hdr);
2114 } else {
2115 /* wct == 12 */
2116 struct smb_com_writex_req *smbw =
2117 (struct smb_com_writex_req *)smb;
2118 inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
2119 put_bcc(wdata->bytes + 5, &smbw->hdr);
2120 iov[0].iov_len += 4; /* pad bigger by four bytes */
2121 }
2122
2123 kref_get(&wdata->refcount);
2124 rc = cifs_call_async(tcon->ses->server, iov, wdata->nr_pages + 1,
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002125 NULL, cifs_writev_callback, wdata, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002126
2127 if (rc == 0)
2128 cifs_stats_inc(&tcon->num_writes);
2129 else
2130 kref_put(&wdata->refcount, cifs_writedata_release);
2131
2132 /* send is done, unmap pages */
2133 for (i = 0; i < wdata->nr_pages; i++)
2134 kunmap(wdata->pages[i]);
2135
2136async_writev_out:
2137 cifs_small_buf_release(smb);
2138 kfree(iov);
2139 return rc;
2140}
2141
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002142int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002143CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002144 unsigned int *nbytes, struct kvec *iov, int n_vec,
2145 const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002146{
2147 int rc = -EACCES;
2148 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08002149 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002150 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08002151 int resp_buf_type = 0;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002152 __u32 pid = io_parms->pid;
2153 __u16 netfid = io_parms->netfid;
2154 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00002155 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002156 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002157
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04002158 *nbytes = 0;
2159
Joe Perchesb6b38f72010-04-21 03:50:45 +00002160 cFYI(1, "write2 at %lld %d bytes", (long long)offset, count);
Steve Frenchff7feac2005-11-15 16:45:16 -08002161
Steve French4c3130e2008-12-09 00:28:16 +00002162 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07002163 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00002164 } else {
Steve French8cc64c62005-10-03 13:49:43 -07002165 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00002166 if ((offset >> 32) > 0) {
2167 /* can not handle big offset for old srv */
2168 return -EIO;
2169 }
2170 }
Steve French8cc64c62005-10-03 13:49:43 -07002171 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002172 if (rc)
2173 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002174
2175 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
2176 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
2177
Linus Torvalds1da177e2005-04-16 15:20:36 -07002178 /* tcon and ses pointer are checked in smb_init */
2179 if (tcon->ses->server == NULL)
2180 return -ECONNABORTED;
2181
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002182 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002183 pSMB->Fid = netfid;
2184 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00002185 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002186 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002187 pSMB->Reserved = 0xFFFFFFFF;
2188 pSMB->WriteMode = 0;
2189 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002190
Linus Torvalds1da177e2005-04-16 15:20:36 -07002191 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00002192 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002193
Steve French3e844692005-10-03 13:37:24 -07002194 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
2195 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002196 /* header + 1 byte pad */
2197 smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
Steve French790fe572007-07-07 19:25:05 +00002198 if (wct == 14)
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002199 inc_rfc1001_len(pSMB, count + 1);
Steve French8cc64c62005-10-03 13:49:43 -07002200 else /* wct == 12 */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002201 inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
Steve French790fe572007-07-07 19:25:05 +00002202 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002203 pSMB->ByteCount = cpu_to_le16(count + 1);
2204 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00002205 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07002206 (struct smb_com_writex_req *)pSMB;
2207 pSMBW->ByteCount = cpu_to_le16(count + 5);
2208 }
Steve French3e844692005-10-03 13:37:24 -07002209 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00002210 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08002211 iov[0].iov_len = smb_hdr_len + 4;
2212 else /* wct == 12 pad bigger by four bytes */
2213 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00002214
Steve French3e844692005-10-03 13:37:24 -07002215
Steve Frenchec637e32005-12-12 20:53:18 -08002216 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French133672e2007-11-13 22:41:37 +00002217 long_op);
Steve Frencha4544342005-08-24 13:59:35 -07002218 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002219 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002220 cFYI(1, "Send error Write2 = %d", rc);
Steve French790fe572007-07-07 19:25:05 +00002221 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08002222 /* presumably this can not happen, but best to be safe */
2223 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002224 } else {
Steve Frenchad7a2922008-02-07 23:25:02 +00002225 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002226 *nbytes = le16_to_cpu(pSMBr->CountHigh);
2227 *nbytes = (*nbytes) << 16;
2228 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05302229
2230 /*
2231 * Mask off high 16 bits when bytes written as returned by the
2232 * server is greater than bytes requested by the client. OS/2
2233 * servers are known to set incorrect CountHigh values.
2234 */
2235 if (*nbytes > count)
2236 *nbytes &= 0xFFFF;
Steve French50c2f752007-07-13 00:33:32 +00002237 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238
Steve French4b8f9302006-02-26 16:41:18 +00002239/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00002240 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002241 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00002242 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002243 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002244
Steve French50c2f752007-07-13 00:33:32 +00002245 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002246 since file handle passed in no longer valid */
2247
2248 return rc;
2249}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002250
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002251int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon,
2252 const __u16 netfid, const __u8 lock_type, const __u32 num_unlock,
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002253 const __u32 num_lock, LOCKING_ANDX_RANGE *buf)
2254{
2255 int rc = 0;
2256 LOCK_REQ *pSMB = NULL;
2257 struct kvec iov[2];
2258 int resp_buf_type;
2259 __u16 count;
2260
2261 cFYI(1, "cifs_lockv num lock %d num unlock %d", num_lock, num_unlock);
2262
2263 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2264 if (rc)
2265 return rc;
2266
2267 pSMB->Timeout = 0;
2268 pSMB->NumberOfLocks = cpu_to_le16(num_lock);
2269 pSMB->NumberOfUnlocks = cpu_to_le16(num_unlock);
2270 pSMB->LockType = lock_type;
2271 pSMB->AndXCommand = 0xFF; /* none */
2272 pSMB->Fid = netfid; /* netfid stays le */
2273
2274 count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2275 inc_rfc1001_len(pSMB, count);
2276 pSMB->ByteCount = cpu_to_le16(count);
2277
2278 iov[0].iov_base = (char *)pSMB;
2279 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 -
2280 (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2281 iov[1].iov_base = (char *)buf;
2282 iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2283
2284 cifs_stats_inc(&tcon->num_locks);
2285 rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP);
2286 if (rc)
2287 cFYI(1, "Send error in cifs_lockv = %d", rc);
2288
2289 return rc;
2290}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002291
Linus Torvalds1da177e2005-04-16 15:20:36 -07002292int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002293CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002294 const __u16 smb_file_id, const __u32 netpid, const __u64 len,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002295 const __u64 offset, const __u32 numUnlock,
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002296 const __u32 numLock, const __u8 lockType,
2297 const bool waitFlag, const __u8 oplock_level)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002298{
2299 int rc = 0;
2300 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002301/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002302 int bytes_returned;
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002303 int flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002304 __u16 count;
2305
Joe Perchesb6b38f72010-04-21 03:50:45 +00002306 cFYI(1, "CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock);
Steve French46810cb2005-04-28 22:41:09 -07002307 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2308
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309 if (rc)
2310 return rc;
2311
Steve French790fe572007-07-07 19:25:05 +00002312 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002313 /* no response expected */
2314 flags = CIFS_ASYNC_OP | CIFS_OBREAK_OP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002315 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00002316 } else if (waitFlag) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002317 flags = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002318 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
2319 } else {
2320 pSMB->Timeout = 0;
2321 }
2322
2323 pSMB->NumberOfLocks = cpu_to_le16(numLock);
2324 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
2325 pSMB->LockType = lockType;
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002326 pSMB->OplockLevel = oplock_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002327 pSMB->AndXCommand = 0xFF; /* none */
2328 pSMB->Fid = smb_file_id; /* netfid stays le */
2329
Steve French790fe572007-07-07 19:25:05 +00002330 if ((numLock != 0) || (numUnlock != 0)) {
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002331 pSMB->Locks[0].Pid = cpu_to_le16(netpid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002332 /* BB where to store pid high? */
2333 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
2334 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
2335 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
2336 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
2337 count = sizeof(LOCKING_ANDX_RANGE);
2338 } else {
2339 /* oplock break */
2340 count = 0;
2341 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002342 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002343 pSMB->ByteCount = cpu_to_le16(count);
2344
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002345 if (waitFlag) {
2346 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002347 (struct smb_hdr *) pSMB, &bytes_returned);
Steve French133672e2007-11-13 22:41:37 +00002348 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002349 } else {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002350 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, flags);
Steve French133672e2007-11-13 22:41:37 +00002351 /* SMB buffer freed by function above */
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002352 }
Steve Frencha4544342005-08-24 13:59:35 -07002353 cifs_stats_inc(&tcon->num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002354 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002355 cFYI(1, "Send error in Lock = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002356
Steve French50c2f752007-07-13 00:33:32 +00002357 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002358 since file handle passed in no longer valid */
2359 return rc;
2360}
2361
2362int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002363CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002364 const __u16 smb_file_id, const __u32 netpid,
2365 const loff_t start_offset, const __u64 len,
2366 struct file_lock *pLockData, const __u16 lock_type,
2367 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00002368{
2369 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2370 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00002371 struct cifs_posix_lock *parm_data;
2372 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00002373 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00002374 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00002375 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00002376 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00002377 struct kvec iov[1];
Steve French08547b02006-02-28 22:39:25 +00002378
Joe Perchesb6b38f72010-04-21 03:50:45 +00002379 cFYI(1, "Posix Lock");
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002380
Steve French08547b02006-02-28 22:39:25 +00002381 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
2382
2383 if (rc)
2384 return rc;
2385
2386 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
2387
Steve French50c2f752007-07-13 00:33:32 +00002388 params = 6;
Steve French08547b02006-02-28 22:39:25 +00002389 pSMB->MaxSetupCount = 0;
2390 pSMB->Reserved = 0;
2391 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00002392 pSMB->Reserved2 = 0;
2393 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2394 offset = param_offset + params;
2395
Steve French08547b02006-02-28 22:39:25 +00002396 count = sizeof(struct cifs_posix_lock);
2397 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002398 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00002399 pSMB->SetupCount = 1;
2400 pSMB->Reserved3 = 0;
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002401 if (pLockData)
Steve French08547b02006-02-28 22:39:25 +00002402 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2403 else
2404 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2405 byte_count = 3 /* pad */ + params + count;
2406 pSMB->DataCount = cpu_to_le16(count);
2407 pSMB->ParameterCount = cpu_to_le16(params);
2408 pSMB->TotalDataCount = pSMB->DataCount;
2409 pSMB->TotalParameterCount = pSMB->ParameterCount;
2410 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00002411 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00002412 (((char *) &pSMB->hdr.Protocol) + offset);
2413
2414 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00002415 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00002416 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00002417 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00002418 pSMB->Timeout = cpu_to_le32(-1);
2419 } else
2420 pSMB->Timeout = 0;
2421
Pavel Shilovsky4f6bcec2011-10-22 15:33:30 +04002422 parm_data->pid = cpu_to_le32(netpid);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002423 parm_data->start = cpu_to_le64(start_offset);
Steve Frenchcec6815a2006-05-30 18:07:17 +00002424 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00002425
2426 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00002427 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00002428 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
2429 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002430 inc_rfc1001_len(pSMB, byte_count);
Steve French08547b02006-02-28 22:39:25 +00002431 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002432 if (waitFlag) {
2433 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2434 (struct smb_hdr *) pSMBr, &bytes_returned);
2435 } else {
Steve French133672e2007-11-13 22:41:37 +00002436 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002437 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French133672e2007-11-13 22:41:37 +00002438 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
2439 &resp_buf_type, timeout);
2440 pSMB = NULL; /* request buf already freed by SendReceive2. Do
2441 not try to free it twice below on exit */
2442 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002443 }
2444
Steve French08547b02006-02-28 22:39:25 +00002445 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002446 cFYI(1, "Send error in Posix Lock = %d", rc);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002447 } else if (pLockData) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002448 /* lock structure can be returned on get */
2449 __u16 data_offset;
2450 __u16 data_count;
2451 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00002452
Jeff Layton820a8032011-05-04 08:05:26 -04002453 if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002454 rc = -EIO; /* bad smb */
2455 goto plk_err_exit;
2456 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002457 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2458 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00002459 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002460 rc = -EIO;
2461 goto plk_err_exit;
2462 }
2463 parm_data = (struct cifs_posix_lock *)
2464 ((char *)&pSMBr->hdr.Protocol + data_offset);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002465 if (parm_data->lock_type == __constant_cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002466 pLockData->fl_type = F_UNLCK;
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002467 else {
2468 if (parm_data->lock_type ==
2469 __constant_cpu_to_le16(CIFS_RDLCK))
2470 pLockData->fl_type = F_RDLCK;
2471 else if (parm_data->lock_type ==
2472 __constant_cpu_to_le16(CIFS_WRLCK))
2473 pLockData->fl_type = F_WRLCK;
2474
Steve French5443d132011-03-13 05:08:25 +00002475 pLockData->fl_start = le64_to_cpu(parm_data->start);
2476 pLockData->fl_end = pLockData->fl_start +
2477 le64_to_cpu(parm_data->length) - 1;
2478 pLockData->fl_pid = le32_to_cpu(parm_data->pid);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002479 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002480 }
Steve French50c2f752007-07-13 00:33:32 +00002481
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002482plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00002483 if (pSMB)
2484 cifs_small_buf_release(pSMB);
2485
Steve French133672e2007-11-13 22:41:37 +00002486 if (resp_buf_type == CIFS_SMALL_BUFFER)
2487 cifs_small_buf_release(iov[0].iov_base);
2488 else if (resp_buf_type == CIFS_LARGE_BUFFER)
2489 cifs_buf_release(iov[0].iov_base);
2490
Steve French08547b02006-02-28 22:39:25 +00002491 /* Note: On -EAGAIN error only caller can retry on handle based calls
2492 since file handle passed in no longer valid */
2493
2494 return rc;
2495}
2496
2497
2498int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002499CIFSSMBClose(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002500{
2501 int rc = 0;
2502 CLOSE_REQ *pSMB = NULL;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002503 cFYI(1, "In CIFSSMBClose");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002504
2505/* do not retry on dead session on close */
2506 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00002507 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002508 return 0;
2509 if (rc)
2510 return rc;
2511
Linus Torvalds1da177e2005-04-16 15:20:36 -07002512 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e2006-10-02 05:53:29 +00002513 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002514 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002515 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002516 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002517 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00002518 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002519 /* EINTR is expected when user ctl-c to kill app */
Joe Perchesb6b38f72010-04-21 03:50:45 +00002520 cERROR(1, "Send error in Close = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002521 }
2522 }
2523
Linus Torvalds1da177e2005-04-16 15:20:36 -07002524 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00002525 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002526 rc = 0;
2527
2528 return rc;
2529}
2530
2531int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002532CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Steve Frenchb298f222009-02-21 21:17:43 +00002533{
2534 int rc = 0;
2535 FLUSH_REQ *pSMB = NULL;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002536 cFYI(1, "In CIFSSMBFlush");
Steve Frenchb298f222009-02-21 21:17:43 +00002537
2538 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
2539 if (rc)
2540 return rc;
2541
2542 pSMB->FileID = (__u16) smb_file_id;
2543 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002544 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frenchb298f222009-02-21 21:17:43 +00002545 cifs_stats_inc(&tcon->num_flushes);
2546 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002547 cERROR(1, "Send error in Flush = %d", rc);
Steve Frenchb298f222009-02-21 21:17:43 +00002548
2549 return rc;
2550}
2551
2552int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002553CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002554 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002555 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002556{
2557 int rc = 0;
2558 RENAME_REQ *pSMB = NULL;
2559 RENAME_RSP *pSMBr = NULL;
2560 int bytes_returned;
2561 int name_len, name_len2;
2562 __u16 count;
2563
Joe Perchesb6b38f72010-04-21 03:50:45 +00002564 cFYI(1, "In CIFSSMBRename");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002565renameRetry:
2566 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
2567 (void **) &pSMBr);
2568 if (rc)
2569 return rc;
2570
2571 pSMB->BufferFormat = 0x04;
2572 pSMB->SearchAttributes =
2573 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2574 ATTR_DIRECTORY);
2575
2576 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2577 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06002578 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, fromName,
2579 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580 name_len++; /* trailing null */
2581 name_len *= 2;
2582 pSMB->OldFileName[name_len] = 0x04; /* pad */
2583 /* protocol requires ASCII signature byte on Unicode string */
2584 pSMB->OldFileName[name_len + 1] = 0x00;
2585 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002586 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2587 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002588 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2589 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002590 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002591 name_len = strnlen(fromName, PATH_MAX);
2592 name_len++; /* trailing null */
2593 strncpy(pSMB->OldFileName, fromName, name_len);
2594 name_len2 = strnlen(toName, PATH_MAX);
2595 name_len2++; /* trailing null */
2596 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2597 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2598 name_len2++; /* trailing null */
2599 name_len2++; /* signature byte */
2600 }
2601
2602 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002603 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002604 pSMB->ByteCount = cpu_to_le16(count);
2605
2606 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2607 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002608 cifs_stats_inc(&tcon->num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002609 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002610 cFYI(1, "Send error in rename = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002611
Linus Torvalds1da177e2005-04-16 15:20:36 -07002612 cifs_buf_release(pSMB);
2613
2614 if (rc == -EAGAIN)
2615 goto renameRetry;
2616
2617 return rc;
2618}
2619
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002620int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002621 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002622 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002623{
2624 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2625 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002626 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002627 char *data_offset;
2628 char dummy_string[30];
2629 int rc = 0;
2630 int bytes_returned = 0;
2631 int len_of_str;
2632 __u16 params, param_offset, offset, count, byte_count;
2633
Joe Perchesb6b38f72010-04-21 03:50:45 +00002634 cFYI(1, "Rename to File by handle");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2636 (void **) &pSMBr);
2637 if (rc)
2638 return rc;
2639
2640 params = 6;
2641 pSMB->MaxSetupCount = 0;
2642 pSMB->Reserved = 0;
2643 pSMB->Flags = 0;
2644 pSMB->Timeout = 0;
2645 pSMB->Reserved2 = 0;
2646 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2647 offset = param_offset + params;
2648
2649 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2650 rename_info = (struct set_file_rename *) data_offset;
2651 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002652 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002653 pSMB->SetupCount = 1;
2654 pSMB->Reserved3 = 0;
2655 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2656 byte_count = 3 /* pad */ + params;
2657 pSMB->ParameterCount = cpu_to_le16(params);
2658 pSMB->TotalParameterCount = pSMB->ParameterCount;
2659 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2660 pSMB->DataOffset = cpu_to_le16(offset);
2661 /* construct random name ".cifs_tmp<inodenum><mid>" */
2662 rename_info->overwrite = cpu_to_le32(1);
2663 rename_info->root_fid = 0;
2664 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002665 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002666 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
Steve Frenchacbbb762012-01-18 22:32:33 -06002667 len_of_str =
2668 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002669 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002670 } else {
Steve Frenchacbbb762012-01-18 22:32:33 -06002671 len_of_str =
2672 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002673 target_name, PATH_MAX, nls_codepage,
2674 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002675 }
2676 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002677 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002678 byte_count += count;
2679 pSMB->DataCount = cpu_to_le16(count);
2680 pSMB->TotalDataCount = pSMB->DataCount;
2681 pSMB->Fid = netfid;
2682 pSMB->InformationLevel =
2683 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2684 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002685 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002686 pSMB->ByteCount = cpu_to_le16(byte_count);
2687 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002688 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002689 cifs_stats_inc(&pTcon->num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002690 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002691 cFYI(1, "Send error in Rename (by file handle) = %d", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07002692
Linus Torvalds1da177e2005-04-16 15:20:36 -07002693 cifs_buf_release(pSMB);
2694
2695 /* Note: On -EAGAIN error only caller can retry on handle based calls
2696 since file handle passed in no longer valid */
2697
2698 return rc;
2699}
2700
2701int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002702CIFSSMBCopy(const unsigned int xid, struct cifs_tcon *tcon,
2703 const char *fromName, const __u16 target_tid, const char *toName,
2704 const int flags, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002705{
2706 int rc = 0;
2707 COPY_REQ *pSMB = NULL;
2708 COPY_RSP *pSMBr = NULL;
2709 int bytes_returned;
2710 int name_len, name_len2;
2711 __u16 count;
2712
Joe Perchesb6b38f72010-04-21 03:50:45 +00002713 cFYI(1, "In CIFSSMBCopy");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002714copyRetry:
2715 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2716 (void **) &pSMBr);
2717 if (rc)
2718 return rc;
2719
2720 pSMB->BufferFormat = 0x04;
2721 pSMB->Tid2 = target_tid;
2722
2723 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2724
2725 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002726 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2727 fromName, PATH_MAX, nls_codepage,
2728 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002729 name_len++; /* trailing null */
2730 name_len *= 2;
2731 pSMB->OldFileName[name_len] = 0x04; /* pad */
2732 /* protocol requires ASCII signature byte on Unicode string */
2733 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002734 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002735 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2736 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002737 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2738 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002739 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002740 name_len = strnlen(fromName, PATH_MAX);
2741 name_len++; /* trailing null */
2742 strncpy(pSMB->OldFileName, fromName, name_len);
2743 name_len2 = strnlen(toName, PATH_MAX);
2744 name_len2++; /* trailing null */
2745 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2746 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2747 name_len2++; /* trailing null */
2748 name_len2++; /* signature byte */
2749 }
2750
2751 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002752 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002753 pSMB->ByteCount = cpu_to_le16(count);
2754
2755 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2756 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2757 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002758 cFYI(1, "Send error in copy = %d with %d files copied",
2759 rc, le16_to_cpu(pSMBr->CopyCount));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002760 }
Steve French0d817bc2008-05-22 02:02:03 +00002761 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002762
2763 if (rc == -EAGAIN)
2764 goto copyRetry;
2765
2766 return rc;
2767}
2768
2769int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002770CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002771 const char *fromName, const char *toName,
2772 const struct nls_table *nls_codepage)
2773{
2774 TRANSACTION2_SPI_REQ *pSMB = NULL;
2775 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2776 char *data_offset;
2777 int name_len;
2778 int name_len_target;
2779 int rc = 0;
2780 int bytes_returned = 0;
2781 __u16 params, param_offset, offset, byte_count;
2782
Joe Perchesb6b38f72010-04-21 03:50:45 +00002783 cFYI(1, "In Symlink Unix style");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002784createSymLinkRetry:
2785 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2786 (void **) &pSMBr);
2787 if (rc)
2788 return rc;
2789
2790 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2791 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06002792 cifs_strtoUTF16((__le16 *) pSMB->FileName, fromName,
2793 /* find define for this maxpathcomponent */
2794 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002795 name_len++; /* trailing null */
2796 name_len *= 2;
2797
Steve French50c2f752007-07-13 00:33:32 +00002798 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002799 name_len = strnlen(fromName, PATH_MAX);
2800 name_len++; /* trailing null */
2801 strncpy(pSMB->FileName, fromName, name_len);
2802 }
2803 params = 6 + name_len;
2804 pSMB->MaxSetupCount = 0;
2805 pSMB->Reserved = 0;
2806 pSMB->Flags = 0;
2807 pSMB->Timeout = 0;
2808 pSMB->Reserved2 = 0;
2809 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002810 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002811 offset = param_offset + params;
2812
2813 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2814 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2815 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06002816 cifs_strtoUTF16((__le16 *) data_offset, toName, PATH_MAX
2817 /* find define for this maxpathcomponent */
2818 , nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002819 name_len_target++; /* trailing null */
2820 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002821 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002822 name_len_target = strnlen(toName, PATH_MAX);
2823 name_len_target++; /* trailing null */
2824 strncpy(data_offset, toName, name_len_target);
2825 }
2826
2827 pSMB->MaxParameterCount = cpu_to_le16(2);
2828 /* BB find exact max on data count below from sess */
2829 pSMB->MaxDataCount = cpu_to_le16(1000);
2830 pSMB->SetupCount = 1;
2831 pSMB->Reserved3 = 0;
2832 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2833 byte_count = 3 /* pad */ + params + name_len_target;
2834 pSMB->DataCount = cpu_to_le16(name_len_target);
2835 pSMB->ParameterCount = cpu_to_le16(params);
2836 pSMB->TotalDataCount = pSMB->DataCount;
2837 pSMB->TotalParameterCount = pSMB->ParameterCount;
2838 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2839 pSMB->DataOffset = cpu_to_le16(offset);
2840 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2841 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002842 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002843 pSMB->ByteCount = cpu_to_le16(byte_count);
2844 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2845 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002846 cifs_stats_inc(&tcon->num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002847 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002848 cFYI(1, "Send error in SetPathInfo create symlink = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002849
Steve French0d817bc2008-05-22 02:02:03 +00002850 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002851
2852 if (rc == -EAGAIN)
2853 goto createSymLinkRetry;
2854
2855 return rc;
2856}
2857
2858int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002859CIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002860 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002861 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002862{
2863 TRANSACTION2_SPI_REQ *pSMB = NULL;
2864 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2865 char *data_offset;
2866 int name_len;
2867 int name_len_target;
2868 int rc = 0;
2869 int bytes_returned = 0;
2870 __u16 params, param_offset, offset, byte_count;
2871
Joe Perchesb6b38f72010-04-21 03:50:45 +00002872 cFYI(1, "In Create Hard link Unix style");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002873createHardLinkRetry:
2874 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2875 (void **) &pSMBr);
2876 if (rc)
2877 return rc;
2878
2879 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002880 name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, toName,
2881 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002882 name_len++; /* trailing null */
2883 name_len *= 2;
2884
Steve French50c2f752007-07-13 00:33:32 +00002885 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002886 name_len = strnlen(toName, PATH_MAX);
2887 name_len++; /* trailing null */
2888 strncpy(pSMB->FileName, toName, name_len);
2889 }
2890 params = 6 + name_len;
2891 pSMB->MaxSetupCount = 0;
2892 pSMB->Reserved = 0;
2893 pSMB->Flags = 0;
2894 pSMB->Timeout = 0;
2895 pSMB->Reserved2 = 0;
2896 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002897 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002898 offset = param_offset + params;
2899
2900 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2901 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2902 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06002903 cifsConvertToUTF16((__le16 *) data_offset, fromName,
2904 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002905 name_len_target++; /* trailing null */
2906 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002907 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002908 name_len_target = strnlen(fromName, PATH_MAX);
2909 name_len_target++; /* trailing null */
2910 strncpy(data_offset, fromName, name_len_target);
2911 }
2912
2913 pSMB->MaxParameterCount = cpu_to_le16(2);
2914 /* BB find exact max on data count below from sess*/
2915 pSMB->MaxDataCount = cpu_to_le16(1000);
2916 pSMB->SetupCount = 1;
2917 pSMB->Reserved3 = 0;
2918 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2919 byte_count = 3 /* pad */ + params + name_len_target;
2920 pSMB->ParameterCount = cpu_to_le16(params);
2921 pSMB->TotalParameterCount = pSMB->ParameterCount;
2922 pSMB->DataCount = cpu_to_le16(name_len_target);
2923 pSMB->TotalDataCount = pSMB->DataCount;
2924 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2925 pSMB->DataOffset = cpu_to_le16(offset);
2926 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2927 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002928 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002929 pSMB->ByteCount = cpu_to_le16(byte_count);
2930 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2931 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002932 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002933 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002934 cFYI(1, "Send error in SetPathInfo (hard link) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002935
2936 cifs_buf_release(pSMB);
2937 if (rc == -EAGAIN)
2938 goto createHardLinkRetry;
2939
2940 return rc;
2941}
2942
2943int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002944CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002945 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002946 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002947{
2948 int rc = 0;
2949 NT_RENAME_REQ *pSMB = NULL;
2950 RENAME_RSP *pSMBr = NULL;
2951 int bytes_returned;
2952 int name_len, name_len2;
2953 __u16 count;
2954
Joe Perchesb6b38f72010-04-21 03:50:45 +00002955 cFYI(1, "In CIFSCreateHardLink");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002956winCreateHardLinkRetry:
2957
2958 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2959 (void **) &pSMBr);
2960 if (rc)
2961 return rc;
2962
2963 pSMB->SearchAttributes =
2964 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2965 ATTR_DIRECTORY);
2966 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2967 pSMB->ClusterCount = 0;
2968
2969 pSMB->BufferFormat = 0x04;
2970
2971 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2972 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06002973 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, fromName,
2974 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002975 name_len++; /* trailing null */
2976 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05002977
2978 /* protocol specifies ASCII buffer format (0x04) for unicode */
2979 pSMB->OldFileName[name_len] = 0x04;
2980 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002981 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002982 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2983 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002984 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2985 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002986 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002987 name_len = strnlen(fromName, PATH_MAX);
2988 name_len++; /* trailing null */
2989 strncpy(pSMB->OldFileName, fromName, name_len);
2990 name_len2 = strnlen(toName, PATH_MAX);
2991 name_len2++; /* trailing null */
2992 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2993 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2994 name_len2++; /* trailing null */
2995 name_len2++; /* signature byte */
2996 }
2997
2998 count = 1 /* string type byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002999 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003000 pSMB->ByteCount = cpu_to_le16(count);
3001
3002 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3003 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003004 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00003005 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003006 cFYI(1, "Send error in hard link (NT rename) = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00003007
Linus Torvalds1da177e2005-04-16 15:20:36 -07003008 cifs_buf_release(pSMB);
3009 if (rc == -EAGAIN)
3010 goto winCreateHardLinkRetry;
3011
3012 return rc;
3013}
3014
3015int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003016CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04003017 const unsigned char *searchName, char **symlinkinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003018 const struct nls_table *nls_codepage)
3019{
3020/* SMB_QUERY_FILE_UNIX_LINK */
3021 TRANSACTION2_QPI_REQ *pSMB = NULL;
3022 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3023 int rc = 0;
3024 int bytes_returned;
3025 int name_len;
3026 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04003027 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003028
Joe Perchesb6b38f72010-04-21 03:50:45 +00003029 cFYI(1, "In QPathSymLinkInfo (Unix) for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003030
3031querySymLinkRetry:
3032 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3033 (void **) &pSMBr);
3034 if (rc)
3035 return rc;
3036
3037 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3038 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003039 cifs_strtoUTF16((__le16 *) pSMB->FileName, searchName,
3040 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003041 name_len++; /* trailing null */
3042 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003043 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003044 name_len = strnlen(searchName, PATH_MAX);
3045 name_len++; /* trailing null */
3046 strncpy(pSMB->FileName, searchName, name_len);
3047 }
3048
3049 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3050 pSMB->TotalDataCount = 0;
3051 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04003052 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003053 pSMB->MaxSetupCount = 0;
3054 pSMB->Reserved = 0;
3055 pSMB->Flags = 0;
3056 pSMB->Timeout = 0;
3057 pSMB->Reserved2 = 0;
3058 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003059 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003060 pSMB->DataCount = 0;
3061 pSMB->DataOffset = 0;
3062 pSMB->SetupCount = 1;
3063 pSMB->Reserved3 = 0;
3064 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3065 byte_count = params + 1 /* pad */ ;
3066 pSMB->TotalParameterCount = cpu_to_le16(params);
3067 pSMB->ParameterCount = pSMB->TotalParameterCount;
3068 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
3069 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003070 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003071 pSMB->ByteCount = cpu_to_le16(byte_count);
3072
3073 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3074 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3075 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003076 cFYI(1, "Send error in QuerySymLinkInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003077 } else {
3078 /* decode response */
3079
3080 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003081 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003082 if (rc || get_bcc(&pSMBr->hdr) < 2)
Jeff Layton460b9692009-04-30 07:17:56 -04003083 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003084 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00003085 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04003086 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003087
Jeff Layton460b9692009-04-30 07:17:56 -04003088 data_start = ((char *) &pSMBr->hdr.Protocol) +
3089 le16_to_cpu(pSMBr->t2.DataOffset);
3090
Steve French0e0d2cf2009-05-01 05:27:32 +00003091 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3092 is_unicode = true;
3093 else
3094 is_unicode = false;
3095
Steve French737b7582005-04-28 22:41:06 -07003096 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchacbbb762012-01-18 22:32:33 -06003097 *symlinkinfo = cifs_strndup_from_utf16(data_start,
3098 count, is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04003099 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04003100 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003101 }
3102 }
3103 cifs_buf_release(pSMB);
3104 if (rc == -EAGAIN)
3105 goto querySymLinkRetry;
3106 return rc;
3107}
3108
Steve Frenchc52a9552011-02-24 06:16:22 +00003109#ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL
3110/*
3111 * Recent Windows versions now create symlinks more frequently
3112 * and they use the "reparse point" mechanism below. We can of course
3113 * do symlinks nicely to Samba and other servers which support the
3114 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
3115 * "MF" symlinks optionally, but for recent Windows we really need to
3116 * reenable the code below and fix the cifs_symlink callers to handle this.
3117 * In the interim this code has been moved to its own config option so
3118 * it is not compiled in by default until callers fixed up and more tested.
3119 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003120int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003121CIFSSMBQueryReparseLinkInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003122 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00003123 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003124 const struct nls_table *nls_codepage)
3125{
3126 int rc = 0;
3127 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00003128 struct smb_com_transaction_ioctl_req *pSMB;
3129 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003130
Joe Perchesb6b38f72010-04-21 03:50:45 +00003131 cFYI(1, "In Windows reparse style QueryLink for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003132 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3133 (void **) &pSMBr);
3134 if (rc)
3135 return rc;
3136
3137 pSMB->TotalParameterCount = 0 ;
3138 pSMB->TotalDataCount = 0;
3139 pSMB->MaxParameterCount = cpu_to_le32(2);
3140 /* BB find exact data count max from sess structure BB */
Jeff Laytonc974bef2011-10-11 06:41:32 -04003141 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003142 pSMB->MaxSetupCount = 4;
3143 pSMB->Reserved = 0;
3144 pSMB->ParameterOffset = 0;
3145 pSMB->DataCount = 0;
3146 pSMB->DataOffset = 0;
3147 pSMB->SetupCount = 4;
3148 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
3149 pSMB->ParameterCount = pSMB->TotalParameterCount;
3150 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
3151 pSMB->IsFsctl = 1; /* FSCTL */
3152 pSMB->IsRootFlag = 0;
3153 pSMB->Fid = fid; /* file handle always le */
3154 pSMB->ByteCount = 0;
3155
3156 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3157 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3158 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003159 cFYI(1, "Send error in QueryReparseLinkInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003160 } else { /* decode response */
3161 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
3162 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
Jeff Layton820a8032011-05-04 08:05:26 -04003163 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
3164 /* BB also check enough total bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003165 rc = -EIO; /* bad smb */
Steve Frenchafe48c32009-05-02 05:25:46 +00003166 goto qreparse_out;
3167 }
3168 if (data_count && (data_count < 2048)) {
3169 char *end_of_smb = 2 /* sizeof byte count */ +
Jeff Layton820a8032011-05-04 08:05:26 -04003170 get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003171
Steve Frenchafe48c32009-05-02 05:25:46 +00003172 struct reparse_data *reparse_buf =
Steve French50c2f752007-07-13 00:33:32 +00003173 (struct reparse_data *)
3174 ((char *)&pSMBr->hdr.Protocol
3175 + data_offset);
Steve Frenchafe48c32009-05-02 05:25:46 +00003176 if ((char *)reparse_buf >= end_of_smb) {
3177 rc = -EIO;
3178 goto qreparse_out;
3179 }
3180 if ((reparse_buf->LinkNamesBuf +
3181 reparse_buf->TargetNameOffset +
3182 reparse_buf->TargetNameLen) > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003183 cFYI(1, "reparse buf beyond SMB");
Steve Frenchafe48c32009-05-02 05:25:46 +00003184 rc = -EIO;
3185 goto qreparse_out;
3186 }
Steve French50c2f752007-07-13 00:33:32 +00003187
Steve Frenchafe48c32009-05-02 05:25:46 +00003188 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3189 cifs_from_ucs2(symlinkinfo, (__le16 *)
Steve French50c2f752007-07-13 00:33:32 +00003190 (reparse_buf->LinkNamesBuf +
3191 reparse_buf->TargetNameOffset),
Steve Frenchafe48c32009-05-02 05:25:46 +00003192 buflen,
3193 reparse_buf->TargetNameLen,
3194 nls_codepage, 0);
3195 } else { /* ASCII names */
3196 strncpy(symlinkinfo,
3197 reparse_buf->LinkNamesBuf +
3198 reparse_buf->TargetNameOffset,
3199 min_t(const int, buflen,
3200 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003201 }
Steve Frenchafe48c32009-05-02 05:25:46 +00003202 } else {
3203 rc = -EIO;
Joe Perchesb6b38f72010-04-21 03:50:45 +00003204 cFYI(1, "Invalid return data count on "
3205 "get reparse info ioctl");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003206 }
Steve Frenchafe48c32009-05-02 05:25:46 +00003207 symlinkinfo[buflen] = 0; /* just in case so the caller
3208 does not go off the end of the buffer */
Joe Perchesb6b38f72010-04-21 03:50:45 +00003209 cFYI(1, "readlink result - %s", symlinkinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003210 }
Steve French989c7e52009-05-02 05:32:20 +00003211
Linus Torvalds1da177e2005-04-16 15:20:36 -07003212qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07003213 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003214
3215 /* Note: On -EAGAIN error only caller can retry on handle based calls
3216 since file handle passed in no longer valid */
3217
3218 return rc;
3219}
Steve Frenchc52a9552011-02-24 06:16:22 +00003220#endif /* CIFS_SYMLINK_EXPERIMENTAL */ /* BB temporarily unused */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003221
3222#ifdef CONFIG_CIFS_POSIX
3223
3224/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00003225static void cifs_convert_ace(posix_acl_xattr_entry *ace,
3226 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003227{
3228 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08003229 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
3230 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
3231 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesb6b38f72010-04-21 03:50:45 +00003232 /* cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003233
3234 return;
3235}
3236
3237/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00003238static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
3239 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003240{
3241 int size = 0;
3242 int i;
3243 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00003244 struct cifs_posix_ace *pACE;
3245 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
3246 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003247
3248 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
3249 return -EOPNOTSUPP;
3250
Steve French790fe572007-07-07 19:25:05 +00003251 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003252 count = le16_to_cpu(cifs_acl->access_entry_count);
3253 pACE = &cifs_acl->ace_array[0];
3254 size = sizeof(struct cifs_posix_acl);
3255 size += sizeof(struct cifs_posix_ace) * count;
3256 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003257 if (size_of_data_area < size) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003258 cFYI(1, "bad CIFS POSIX ACL size %d vs. %d",
3259 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003260 return -EINVAL;
3261 }
Steve French790fe572007-07-07 19:25:05 +00003262 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003263 count = le16_to_cpu(cifs_acl->access_entry_count);
3264 size = sizeof(struct cifs_posix_acl);
3265 size += sizeof(struct cifs_posix_ace) * count;
3266/* skip past access ACEs to get to default ACEs */
3267 pACE = &cifs_acl->ace_array[count];
3268 count = le16_to_cpu(cifs_acl->default_entry_count);
3269 size += sizeof(struct cifs_posix_ace) * count;
3270 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003271 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003272 return -EINVAL;
3273 } else {
3274 /* illegal type */
3275 return -EINVAL;
3276 }
3277
3278 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00003279 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00003280 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00003281 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003282 return -ERANGE;
3283 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08003284 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00003285 for (i = 0; i < count ; i++) {
3286 cifs_convert_ace(&local_acl->a_entries[i], pACE);
3287 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003288 }
3289 }
3290 return size;
3291}
3292
Steve French50c2f752007-07-13 00:33:32 +00003293static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
3294 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003295{
3296 __u16 rc = 0; /* 0 = ACL converted ok */
3297
Steve Frenchff7feac2005-11-15 16:45:16 -08003298 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
3299 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003300 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00003301 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003302 /* Probably no need to le convert -1 on any arch but can not hurt */
3303 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00003304 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08003305 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesb6b38f72010-04-21 03:50:45 +00003306 /*cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id);*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003307 return rc;
3308}
3309
3310/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00003311static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
3312 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003313{
3314 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00003315 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
3316 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003317 int count;
3318 int i;
3319
Steve French790fe572007-07-07 19:25:05 +00003320 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003321 return 0;
3322
3323 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesb6b38f72010-04-21 03:50:45 +00003324 cFYI(1, "setting acl with %d entries from buf of length %d and "
Steve French63135e02007-07-17 17:34:02 +00003325 "version of %d",
Joe Perchesb6b38f72010-04-21 03:50:45 +00003326 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00003327 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003328 cFYI(1, "unknown POSIX ACL version %d",
3329 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003330 return 0;
3331 }
3332 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00003333 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08003334 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00003335 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08003336 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003337 else {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003338 cFYI(1, "unknown ACL type %d", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003339 return 0;
3340 }
Steve French50c2f752007-07-13 00:33:32 +00003341 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003342 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
3343 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00003344 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003345 /* ACE not converted */
3346 break;
3347 }
3348 }
Steve French790fe572007-07-07 19:25:05 +00003349 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003350 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
3351 rc += sizeof(struct cifs_posix_acl);
3352 /* BB add check to make sure ACL does not overflow SMB */
3353 }
3354 return rc;
3355}
3356
3357int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003358CIFSSMBGetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003359 const unsigned char *searchName,
3360 char *acl_inf, const int buflen, const int acl_type,
3361 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003362{
3363/* SMB_QUERY_POSIX_ACL */
3364 TRANSACTION2_QPI_REQ *pSMB = NULL;
3365 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3366 int rc = 0;
3367 int bytes_returned;
3368 int name_len;
3369 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00003370
Joe Perchesb6b38f72010-04-21 03:50:45 +00003371 cFYI(1, "In GetPosixACL (Unix) for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003372
3373queryAclRetry:
3374 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3375 (void **) &pSMBr);
3376 if (rc)
3377 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003378
Linus Torvalds1da177e2005-04-16 15:20:36 -07003379 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3380 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003381 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3382 searchName, PATH_MAX, nls_codepage,
3383 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003384 name_len++; /* trailing null */
3385 name_len *= 2;
3386 pSMB->FileName[name_len] = 0;
3387 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00003388 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003389 name_len = strnlen(searchName, PATH_MAX);
3390 name_len++; /* trailing null */
3391 strncpy(pSMB->FileName, searchName, name_len);
3392 }
3393
3394 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3395 pSMB->TotalDataCount = 0;
3396 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00003397 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003398 pSMB->MaxDataCount = cpu_to_le16(4000);
3399 pSMB->MaxSetupCount = 0;
3400 pSMB->Reserved = 0;
3401 pSMB->Flags = 0;
3402 pSMB->Timeout = 0;
3403 pSMB->Reserved2 = 0;
3404 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003405 offsetof(struct smb_com_transaction2_qpi_req,
3406 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003407 pSMB->DataCount = 0;
3408 pSMB->DataOffset = 0;
3409 pSMB->SetupCount = 1;
3410 pSMB->Reserved3 = 0;
3411 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3412 byte_count = params + 1 /* pad */ ;
3413 pSMB->TotalParameterCount = cpu_to_le16(params);
3414 pSMB->ParameterCount = pSMB->TotalParameterCount;
3415 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
3416 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003417 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003418 pSMB->ByteCount = cpu_to_le16(byte_count);
3419
3420 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3421 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08003422 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003423 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003424 cFYI(1, "Send error in Query POSIX ACL = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003425 } else {
3426 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00003427
Linus Torvalds1da177e2005-04-16 15:20:36 -07003428 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003429 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003430 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003431 rc = -EIO; /* bad smb */
3432 else {
3433 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3434 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3435 rc = cifs_copy_posix_acl(acl_inf,
3436 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00003437 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003438 }
3439 }
3440 cifs_buf_release(pSMB);
3441 if (rc == -EAGAIN)
3442 goto queryAclRetry;
3443 return rc;
3444}
3445
3446int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003447CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003448 const unsigned char *fileName,
3449 const char *local_acl, const int buflen,
3450 const int acl_type,
3451 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003452{
3453 struct smb_com_transaction2_spi_req *pSMB = NULL;
3454 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3455 char *parm_data;
3456 int name_len;
3457 int rc = 0;
3458 int bytes_returned = 0;
3459 __u16 params, byte_count, data_count, param_offset, offset;
3460
Joe Perchesb6b38f72010-04-21 03:50:45 +00003461 cFYI(1, "In SetPosixACL (Unix) for path %s", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003462setAclRetry:
3463 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003464 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003465 if (rc)
3466 return rc;
3467 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3468 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003469 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
3470 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003471 name_len++; /* trailing null */
3472 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003473 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003474 name_len = strnlen(fileName, PATH_MAX);
3475 name_len++; /* trailing null */
3476 strncpy(pSMB->FileName, fileName, name_len);
3477 }
3478 params = 6 + name_len;
3479 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003480 /* BB find max SMB size from sess */
3481 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003482 pSMB->MaxSetupCount = 0;
3483 pSMB->Reserved = 0;
3484 pSMB->Flags = 0;
3485 pSMB->Timeout = 0;
3486 pSMB->Reserved2 = 0;
3487 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003488 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003489 offset = param_offset + params;
3490 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
3491 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3492
3493 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00003494 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003495
Steve French790fe572007-07-07 19:25:05 +00003496 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003497 rc = -EOPNOTSUPP;
3498 goto setACLerrorExit;
3499 }
3500 pSMB->DataOffset = cpu_to_le16(offset);
3501 pSMB->SetupCount = 1;
3502 pSMB->Reserved3 = 0;
3503 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3504 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
3505 byte_count = 3 /* pad */ + params + data_count;
3506 pSMB->DataCount = cpu_to_le16(data_count);
3507 pSMB->TotalDataCount = pSMB->DataCount;
3508 pSMB->ParameterCount = cpu_to_le16(params);
3509 pSMB->TotalParameterCount = pSMB->ParameterCount;
3510 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003511 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003512 pSMB->ByteCount = cpu_to_le16(byte_count);
3513 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003514 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003515 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003516 cFYI(1, "Set POSIX ACL returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003517
3518setACLerrorExit:
3519 cifs_buf_release(pSMB);
3520 if (rc == -EAGAIN)
3521 goto setAclRetry;
3522 return rc;
3523}
3524
Steve Frenchf654bac2005-04-28 22:41:04 -07003525/* BB fix tabs in this function FIXME BB */
3526int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003527CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00003528 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07003529{
Steve French50c2f752007-07-13 00:33:32 +00003530 int rc = 0;
3531 struct smb_t2_qfi_req *pSMB = NULL;
3532 struct smb_t2_qfi_rsp *pSMBr = NULL;
3533 int bytes_returned;
3534 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07003535
Joe Perchesb6b38f72010-04-21 03:50:45 +00003536 cFYI(1, "In GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00003537 if (tcon == NULL)
3538 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07003539
3540GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003541 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3542 (void **) &pSMBr);
3543 if (rc)
3544 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003545
Steve Frenchad7a2922008-02-07 23:25:02 +00003546 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003547 pSMB->t2.TotalDataCount = 0;
3548 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3549 /* BB find exact max data count below from sess structure BB */
3550 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3551 pSMB->t2.MaxSetupCount = 0;
3552 pSMB->t2.Reserved = 0;
3553 pSMB->t2.Flags = 0;
3554 pSMB->t2.Timeout = 0;
3555 pSMB->t2.Reserved2 = 0;
3556 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3557 Fid) - 4);
3558 pSMB->t2.DataCount = 0;
3559 pSMB->t2.DataOffset = 0;
3560 pSMB->t2.SetupCount = 1;
3561 pSMB->t2.Reserved3 = 0;
3562 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3563 byte_count = params + 1 /* pad */ ;
3564 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3565 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3566 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3567 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003568 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003569 inc_rfc1001_len(pSMB, byte_count);
Steve French790fe572007-07-07 19:25:05 +00003570 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003571
Steve French790fe572007-07-07 19:25:05 +00003572 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3573 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3574 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003575 cFYI(1, "error %d in GetExtAttr", rc);
Steve French790fe572007-07-07 19:25:05 +00003576 } else {
3577 /* decode response */
3578 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003579 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003580 if (rc || get_bcc(&pSMBr->hdr) < 2)
Steve French790fe572007-07-07 19:25:05 +00003581 /* If rc should we check for EOPNOSUPP and
3582 disable the srvino flag? or in caller? */
3583 rc = -EIO; /* bad smb */
3584 else {
3585 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3586 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3587 struct file_chattr_info *pfinfo;
3588 /* BB Do we need a cast or hash here ? */
3589 if (count != 16) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003590 cFYI(1, "Illegal size ret in GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00003591 rc = -EIO;
3592 goto GetExtAttrOut;
3593 }
3594 pfinfo = (struct file_chattr_info *)
3595 (data_offset + (char *) &pSMBr->hdr.Protocol);
3596 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003597 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003598 }
3599 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003600GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003601 cifs_buf_release(pSMB);
3602 if (rc == -EAGAIN)
3603 goto GetExtAttrRetry;
3604 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003605}
3606
Steve Frenchf654bac2005-04-28 22:41:04 -07003607#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003608
Jeff Layton79df1ba2010-12-06 12:52:08 -05003609#ifdef CONFIG_CIFS_ACL
3610/*
3611 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3612 * all NT TRANSACTS that we init here have total parm and data under about 400
3613 * bytes (to fit in small cifs buffer size), which is the case so far, it
3614 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3615 * returned setup area) and MaxParameterCount (returned parms size) must be set
3616 * by caller
3617 */
3618static int
3619smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French96daf2b2011-05-27 04:34:02 +00003620 const int parm_len, struct cifs_tcon *tcon,
Jeff Layton79df1ba2010-12-06 12:52:08 -05003621 void **ret_buf)
3622{
3623 int rc;
3624 __u32 temp_offset;
3625 struct smb_com_ntransact_req *pSMB;
3626
3627 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3628 (void **)&pSMB);
3629 if (rc)
3630 return rc;
3631 *ret_buf = (void *)pSMB;
3632 pSMB->Reserved = 0;
3633 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3634 pSMB->TotalDataCount = 0;
Jeff Laytonc974bef2011-10-11 06:41:32 -04003635 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003636 pSMB->ParameterCount = pSMB->TotalParameterCount;
3637 pSMB->DataCount = pSMB->TotalDataCount;
3638 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3639 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3640 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3641 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3642 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3643 pSMB->SubCommand = cpu_to_le16(sub_command);
3644 return 0;
3645}
3646
3647static int
3648validate_ntransact(char *buf, char **ppparm, char **ppdata,
3649 __u32 *pparmlen, __u32 *pdatalen)
3650{
3651 char *end_of_smb;
3652 __u32 data_count, data_offset, parm_count, parm_offset;
3653 struct smb_com_ntransact_rsp *pSMBr;
Jeff Layton820a8032011-05-04 08:05:26 -04003654 u16 bcc;
Jeff Layton79df1ba2010-12-06 12:52:08 -05003655
3656 *pdatalen = 0;
3657 *pparmlen = 0;
3658
3659 if (buf == NULL)
3660 return -EINVAL;
3661
3662 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3663
Jeff Layton820a8032011-05-04 08:05:26 -04003664 bcc = get_bcc(&pSMBr->hdr);
3665 end_of_smb = 2 /* sizeof byte count */ + bcc +
Jeff Layton79df1ba2010-12-06 12:52:08 -05003666 (char *)&pSMBr->ByteCount;
3667
3668 data_offset = le32_to_cpu(pSMBr->DataOffset);
3669 data_count = le32_to_cpu(pSMBr->DataCount);
3670 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3671 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3672
3673 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3674 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3675
3676 /* should we also check that parm and data areas do not overlap? */
3677 if (*ppparm > end_of_smb) {
3678 cFYI(1, "parms start after end of smb");
3679 return -EINVAL;
3680 } else if (parm_count + *ppparm > end_of_smb) {
3681 cFYI(1, "parm end after end of smb");
3682 return -EINVAL;
3683 } else if (*ppdata > end_of_smb) {
3684 cFYI(1, "data starts after end of smb");
3685 return -EINVAL;
3686 } else if (data_count + *ppdata > end_of_smb) {
3687 cFYI(1, "data %p + count %d (%p) past smb end %p start %p",
3688 *ppdata, data_count, (data_count + *ppdata),
3689 end_of_smb, pSMBr);
3690 return -EINVAL;
Jeff Layton820a8032011-05-04 08:05:26 -04003691 } else if (parm_count + data_count > bcc) {
Jeff Layton79df1ba2010-12-06 12:52:08 -05003692 cFYI(1, "parm count and data count larger than SMB");
3693 return -EINVAL;
3694 }
3695 *pdatalen = data_count;
3696 *pparmlen = parm_count;
3697 return 0;
3698}
3699
Steve French0a4b92c2006-01-12 15:44:21 -08003700/* Get Security Descriptor (by handle) from remote server for a file or dir */
3701int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003702CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003703 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003704{
3705 int rc = 0;
3706 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003707 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003708 struct kvec iov[1];
3709
Joe Perchesb6b38f72010-04-21 03:50:45 +00003710 cFYI(1, "GetCifsACL");
Steve French0a4b92c2006-01-12 15:44:21 -08003711
Steve French630f3f0c2007-10-25 21:17:17 +00003712 *pbuflen = 0;
3713 *acl_inf = NULL;
3714
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003715 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003716 8 /* parm len */, tcon, (void **) &pSMB);
3717 if (rc)
3718 return rc;
3719
3720 pSMB->MaxParameterCount = cpu_to_le32(4);
3721 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3722 pSMB->MaxSetupCount = 0;
3723 pSMB->Fid = fid; /* file handle always le */
3724 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3725 CIFS_ACL_DACL);
3726 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003727 inc_rfc1001_len(pSMB, 11);
Steve French0a4b92c2006-01-12 15:44:21 -08003728 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003729 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French0a4b92c2006-01-12 15:44:21 -08003730
Steve Frencha761ac52007-10-18 21:45:27 +00003731 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Jeff Layton77499812011-01-11 07:24:23 -05003732 0);
Steve French0a4b92c2006-01-12 15:44:21 -08003733 cifs_stats_inc(&tcon->num_acl_get);
3734 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003735 cFYI(1, "Send error in QuerySecDesc = %d", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08003736 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003737 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003738 __u32 parm_len;
3739 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003740 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003741 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003742
3743/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003744 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003745 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003746 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003747 goto qsec_out;
3748 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3749
Joe Perchesb6b38f72010-04-21 03:50:45 +00003750 cFYI(1, "smb %p parm %p data %p", pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08003751
3752 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3753 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003754 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003755 goto qsec_out;
3756 }
3757
3758/* BB check that data area is minimum length and as big as acl_len */
3759
Steve Frenchaf6f4612007-10-16 18:40:37 +00003760 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003761 if (acl_len != *pbuflen) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003762 cERROR(1, "acl length %d does not match %d",
3763 acl_len, *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003764 if (*pbuflen > acl_len)
3765 *pbuflen = acl_len;
3766 }
Steve French0a4b92c2006-01-12 15:44:21 -08003767
Steve French630f3f0c2007-10-25 21:17:17 +00003768 /* check if buffer is big enough for the acl
3769 header followed by the smallest SID */
3770 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3771 (*pbuflen >= 64 * 1024)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003772 cERROR(1, "bad acl length %d", *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003773 rc = -EINVAL;
3774 *pbuflen = 0;
3775 } else {
3776 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3777 if (*acl_inf == NULL) {
3778 *pbuflen = 0;
3779 rc = -ENOMEM;
3780 }
3781 memcpy(*acl_inf, pdata, *pbuflen);
3782 }
Steve French0a4b92c2006-01-12 15:44:21 -08003783 }
3784qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003785 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003786 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003787 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003788 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003789/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003790 return rc;
3791}
Steve French97837582007-12-31 07:47:21 +00003792
3793int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003794CIFSSMBSetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003795 struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
Steve French97837582007-12-31 07:47:21 +00003796{
3797 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3798 int rc = 0;
3799 int bytes_returned = 0;
3800 SET_SEC_DESC_REQ *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003801 void *pSMBr;
Steve French97837582007-12-31 07:47:21 +00003802
3803setCifsAclRetry:
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003804 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, &pSMBr);
Steve French97837582007-12-31 07:47:21 +00003805 if (rc)
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003806 return rc;
Steve French97837582007-12-31 07:47:21 +00003807
3808 pSMB->MaxSetupCount = 0;
3809 pSMB->Reserved = 0;
3810
3811 param_count = 8;
3812 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3813 data_count = acllen;
3814 data_offset = param_offset + param_count;
3815 byte_count = 3 /* pad */ + param_count;
3816
3817 pSMB->DataCount = cpu_to_le32(data_count);
3818 pSMB->TotalDataCount = pSMB->DataCount;
3819 pSMB->MaxParameterCount = cpu_to_le32(4);
3820 pSMB->MaxDataCount = cpu_to_le32(16384);
3821 pSMB->ParameterCount = cpu_to_le32(param_count);
3822 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3823 pSMB->TotalParameterCount = pSMB->ParameterCount;
3824 pSMB->DataOffset = cpu_to_le32(data_offset);
3825 pSMB->SetupCount = 0;
3826 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3827 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3828
3829 pSMB->Fid = fid; /* file handle always le */
3830 pSMB->Reserved2 = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003831 pSMB->AclFlags = cpu_to_le32(aclflag);
Steve French97837582007-12-31 07:47:21 +00003832
3833 if (pntsd && acllen) {
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003834 memcpy((char *)pSMBr + offsetof(struct smb_hdr, Protocol) +
3835 data_offset, pntsd, acllen);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003836 inc_rfc1001_len(pSMB, byte_count + data_count);
Steve French97837582007-12-31 07:47:21 +00003837 } else
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003838 inc_rfc1001_len(pSMB, byte_count);
Steve French97837582007-12-31 07:47:21 +00003839
3840 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3841 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3842
Joe Perchesb6b38f72010-04-21 03:50:45 +00003843 cFYI(1, "SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00003844 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003845 cFYI(1, "Set CIFS ACL returned %d", rc);
Steve French97837582007-12-31 07:47:21 +00003846 cifs_buf_release(pSMB);
3847
3848 if (rc == -EAGAIN)
3849 goto setCifsAclRetry;
3850
3851 return (rc);
3852}
3853
Jeff Layton79df1ba2010-12-06 12:52:08 -05003854#endif /* CONFIG_CIFS_ACL */
Steve French0a4b92c2006-01-12 15:44:21 -08003855
Steve French6b8edfe2005-08-23 20:26:03 -07003856/* Legacy Query Path Information call for lookup to old servers such
3857 as Win9x/WinME */
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003858int SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003859 const unsigned char *searchName,
3860 FILE_ALL_INFO *pFinfo,
3861 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003862{
Steve Frenchad7a2922008-02-07 23:25:02 +00003863 QUERY_INFORMATION_REQ *pSMB;
3864 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003865 int rc = 0;
3866 int bytes_returned;
3867 int name_len;
3868
Joe Perchesb6b38f72010-04-21 03:50:45 +00003869 cFYI(1, "In SMBQPath path %s", searchName);
Steve French6b8edfe2005-08-23 20:26:03 -07003870QInfRetry:
3871 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003872 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003873 if (rc)
3874 return rc;
3875
3876 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3877 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003878 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3879 searchName, PATH_MAX, nls_codepage,
3880 remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003881 name_len++; /* trailing null */
3882 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003883 } else {
Steve French6b8edfe2005-08-23 20:26:03 -07003884 name_len = strnlen(searchName, PATH_MAX);
3885 name_len++; /* trailing null */
3886 strncpy(pSMB->FileName, searchName, name_len);
3887 }
3888 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003889 name_len++; /* account for buffer type byte */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003890 inc_rfc1001_len(pSMB, (__u16)name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07003891 pSMB->ByteCount = cpu_to_le16(name_len);
3892
3893 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003894 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003895 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003896 cFYI(1, "Send error in QueryInfo = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00003897 } else if (pFinfo) {
Steve French1bd5bbc2006-09-28 03:35:57 +00003898 struct timespec ts;
3899 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00003900
3901 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003902 /* BB FIXME - add time zone adjustment BB */
Steve French6b8edfe2005-08-23 20:26:03 -07003903 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003904 ts.tv_nsec = 0;
3905 ts.tv_sec = time;
3906 /* decode time fields */
Al Viro733f99a2006-10-14 16:48:26 +01003907 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
Steve French1bd5bbc2006-09-28 03:35:57 +00003908 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3909 pFinfo->LastAccessTime = 0;
Steve French70ca7342005-09-22 16:32:06 -07003910 pFinfo->AllocationSize =
3911 cpu_to_le64(le32_to_cpu(pSMBr->size));
3912 pFinfo->EndOfFile = pFinfo->AllocationSize;
3913 pFinfo->Attributes =
3914 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003915 } else
3916 rc = -EIO; /* bad buffer passed in */
3917
3918 cifs_buf_release(pSMB);
3919
3920 if (rc == -EAGAIN)
3921 goto QInfRetry;
3922
3923 return rc;
3924}
3925
Jeff Laytonbcd53572010-02-12 07:44:16 -05003926int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003927CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonbcd53572010-02-12 07:44:16 -05003928 u16 netfid, FILE_ALL_INFO *pFindData)
3929{
3930 struct smb_t2_qfi_req *pSMB = NULL;
3931 struct smb_t2_qfi_rsp *pSMBr = NULL;
3932 int rc = 0;
3933 int bytes_returned;
3934 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07003935
Jeff Laytonbcd53572010-02-12 07:44:16 -05003936QFileInfoRetry:
3937 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3938 (void **) &pSMBr);
3939 if (rc)
3940 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07003941
Jeff Laytonbcd53572010-02-12 07:44:16 -05003942 params = 2 /* level */ + 2 /* fid */;
3943 pSMB->t2.TotalDataCount = 0;
3944 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3945 /* BB find exact max data count below from sess structure BB */
3946 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3947 pSMB->t2.MaxSetupCount = 0;
3948 pSMB->t2.Reserved = 0;
3949 pSMB->t2.Flags = 0;
3950 pSMB->t2.Timeout = 0;
3951 pSMB->t2.Reserved2 = 0;
3952 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3953 Fid) - 4);
3954 pSMB->t2.DataCount = 0;
3955 pSMB->t2.DataOffset = 0;
3956 pSMB->t2.SetupCount = 1;
3957 pSMB->t2.Reserved3 = 0;
3958 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3959 byte_count = params + 1 /* pad */ ;
3960 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3961 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3962 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3963 pSMB->Pad = 0;
3964 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003965 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003966
3967 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3968 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3969 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00003970 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003971 } else { /* decode response */
3972 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3973
3974 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3975 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04003976 else if (get_bcc(&pSMBr->hdr) < 40)
Jeff Laytonbcd53572010-02-12 07:44:16 -05003977 rc = -EIO; /* bad smb */
3978 else if (pFindData) {
3979 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3980 memcpy((char *) pFindData,
3981 (char *) &pSMBr->hdr.Protocol +
3982 data_offset, sizeof(FILE_ALL_INFO));
3983 } else
3984 rc = -ENOMEM;
3985 }
3986 cifs_buf_release(pSMB);
3987 if (rc == -EAGAIN)
3988 goto QFileInfoRetry;
3989
3990 return rc;
3991}
Steve French6b8edfe2005-08-23 20:26:03 -07003992
Linus Torvalds1da177e2005-04-16 15:20:36 -07003993int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003994CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003995 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003996 FILE_ALL_INFO *pFindData,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003997 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003998 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003999{
4000/* level 263 SMB_QUERY_FILE_ALL_INFO */
4001 TRANSACTION2_QPI_REQ *pSMB = NULL;
4002 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4003 int rc = 0;
4004 int bytes_returned;
4005 int name_len;
4006 __u16 params, byte_count;
4007
Joe Perchesb6b38f72010-04-21 03:50:45 +00004008/* cFYI(1, "In QPathInfo path %s", searchName); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004009QPathInfoRetry:
4010 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4011 (void **) &pSMBr);
4012 if (rc)
4013 return rc;
4014
4015 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4016 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004017 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4018 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004019 name_len++; /* trailing null */
4020 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004021 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004022 name_len = strnlen(searchName, PATH_MAX);
4023 name_len++; /* trailing null */
4024 strncpy(pSMB->FileName, searchName, name_len);
4025 }
4026
Steve French50c2f752007-07-13 00:33:32 +00004027 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004028 pSMB->TotalDataCount = 0;
4029 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004030 /* BB find exact max SMB PDU from sess structure BB */
4031 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004032 pSMB->MaxSetupCount = 0;
4033 pSMB->Reserved = 0;
4034 pSMB->Flags = 0;
4035 pSMB->Timeout = 0;
4036 pSMB->Reserved2 = 0;
4037 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004038 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004039 pSMB->DataCount = 0;
4040 pSMB->DataOffset = 0;
4041 pSMB->SetupCount = 1;
4042 pSMB->Reserved3 = 0;
4043 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4044 byte_count = params + 1 /* pad */ ;
4045 pSMB->TotalParameterCount = cpu_to_le16(params);
4046 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00004047 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004048 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
4049 else
4050 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004051 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004052 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004053 pSMB->ByteCount = cpu_to_le16(byte_count);
4054
4055 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4056 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4057 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004058 cFYI(1, "Send error in QPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004059 } else { /* decode response */
4060 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4061
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004062 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4063 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004064 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004065 rc = -EIO; /* bad smb */
Jeff Layton820a8032011-05-04 08:05:26 -04004066 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
Steve French50c2f752007-07-13 00:33:32 +00004067 rc = -EIO; /* 24 or 26 expected but we do not read
4068 last field */
4069 else if (pFindData) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004070 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004071 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00004072
4073 /* On legacy responses we do not read the last field,
4074 EAsize, fortunately since it varies by subdialect and
4075 also note it differs on Set vs. Get, ie two bytes or 4
4076 bytes depending but we don't care here */
4077 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004078 size = sizeof(FILE_INFO_STANDARD);
4079 else
4080 size = sizeof(FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004081 memcpy((char *) pFindData,
4082 (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004083 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004084 } else
4085 rc = -ENOMEM;
4086 }
4087 cifs_buf_release(pSMB);
4088 if (rc == -EAGAIN)
4089 goto QPathInfoRetry;
4090
4091 return rc;
4092}
4093
4094int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004095CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004096 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
4097{
4098 struct smb_t2_qfi_req *pSMB = NULL;
4099 struct smb_t2_qfi_rsp *pSMBr = NULL;
4100 int rc = 0;
4101 int bytes_returned;
4102 __u16 params, byte_count;
4103
4104UnixQFileInfoRetry:
4105 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4106 (void **) &pSMBr);
4107 if (rc)
4108 return rc;
4109
4110 params = 2 /* level */ + 2 /* fid */;
4111 pSMB->t2.TotalDataCount = 0;
4112 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4113 /* BB find exact max data count below from sess structure BB */
4114 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4115 pSMB->t2.MaxSetupCount = 0;
4116 pSMB->t2.Reserved = 0;
4117 pSMB->t2.Flags = 0;
4118 pSMB->t2.Timeout = 0;
4119 pSMB->t2.Reserved2 = 0;
4120 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4121 Fid) - 4);
4122 pSMB->t2.DataCount = 0;
4123 pSMB->t2.DataOffset = 0;
4124 pSMB->t2.SetupCount = 1;
4125 pSMB->t2.Reserved3 = 0;
4126 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4127 byte_count = params + 1 /* pad */ ;
4128 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4129 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4130 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4131 pSMB->Pad = 0;
4132 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004133 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004134
4135 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4136 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4137 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00004138 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004139 } else { /* decode response */
4140 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4141
Jeff Layton820a8032011-05-04 08:05:26 -04004142 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004143 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response. "
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004144 "Unix Extensions can be disabled on mount "
Steve Frenchf19159d2010-04-21 04:12:10 +00004145 "by specifying the nosfu mount option.");
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004146 rc = -EIO; /* bad smb */
4147 } else {
4148 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4149 memcpy((char *) pFindData,
4150 (char *) &pSMBr->hdr.Protocol +
4151 data_offset,
4152 sizeof(FILE_UNIX_BASIC_INFO));
4153 }
4154 }
4155
4156 cifs_buf_release(pSMB);
4157 if (rc == -EAGAIN)
4158 goto UnixQFileInfoRetry;
4159
4160 return rc;
4161}
4162
4163int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004164CIFSSMBUnixQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004165 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00004166 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07004167 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004168{
4169/* SMB_QUERY_FILE_UNIX_BASIC */
4170 TRANSACTION2_QPI_REQ *pSMB = NULL;
4171 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4172 int rc = 0;
4173 int bytes_returned = 0;
4174 int name_len;
4175 __u16 params, byte_count;
4176
Joe Perchesb6b38f72010-04-21 03:50:45 +00004177 cFYI(1, "In QPathInfo (Unix) the path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004178UnixQPathInfoRetry:
4179 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4180 (void **) &pSMBr);
4181 if (rc)
4182 return rc;
4183
4184 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4185 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004186 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4187 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004188 name_len++; /* trailing null */
4189 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004190 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004191 name_len = strnlen(searchName, PATH_MAX);
4192 name_len++; /* trailing null */
4193 strncpy(pSMB->FileName, searchName, name_len);
4194 }
4195
Steve French50c2f752007-07-13 00:33:32 +00004196 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004197 pSMB->TotalDataCount = 0;
4198 pSMB->MaxParameterCount = cpu_to_le16(2);
4199 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00004200 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004201 pSMB->MaxSetupCount = 0;
4202 pSMB->Reserved = 0;
4203 pSMB->Flags = 0;
4204 pSMB->Timeout = 0;
4205 pSMB->Reserved2 = 0;
4206 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004207 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004208 pSMB->DataCount = 0;
4209 pSMB->DataOffset = 0;
4210 pSMB->SetupCount = 1;
4211 pSMB->Reserved3 = 0;
4212 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4213 byte_count = params + 1 /* pad */ ;
4214 pSMB->TotalParameterCount = cpu_to_le16(params);
4215 pSMB->ParameterCount = pSMB->TotalParameterCount;
4216 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4217 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004218 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004219 pSMB->ByteCount = cpu_to_le16(byte_count);
4220
4221 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4222 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4223 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004224 cFYI(1, "Send error in QPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004225 } else { /* decode response */
4226 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4227
Jeff Layton820a8032011-05-04 08:05:26 -04004228 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004229 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response. "
Steve French1e71f252007-09-20 15:30:07 +00004230 "Unix Extensions can be disabled on mount "
Joe Perchesb6b38f72010-04-21 03:50:45 +00004231 "by specifying the nosfu mount option.");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004232 rc = -EIO; /* bad smb */
4233 } else {
4234 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4235 memcpy((char *) pFindData,
4236 (char *) &pSMBr->hdr.Protocol +
4237 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00004238 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004239 }
4240 }
4241 cifs_buf_release(pSMB);
4242 if (rc == -EAGAIN)
4243 goto UnixQPathInfoRetry;
4244
4245 return rc;
4246}
4247
Linus Torvalds1da177e2005-04-16 15:20:36 -07004248/* xid, tcon, searchName and codepage are input parms, rest are returned */
4249int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004250CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004251 const char *searchName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004252 const struct nls_table *nls_codepage,
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004253 __u16 *pnetfid, __u16 search_flags,
Steve French50c2f752007-07-13 00:33:32 +00004254 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004255{
4256/* level 257 SMB_ */
4257 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
4258 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004259 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004260 int rc = 0;
4261 int bytes_returned = 0;
4262 int name_len;
4263 __u16 params, byte_count;
4264
Joe Perchesb6b38f72010-04-21 03:50:45 +00004265 cFYI(1, "In FindFirst for %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004266
4267findFirstRetry:
4268 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4269 (void **) &pSMBr);
4270 if (rc)
4271 return rc;
4272
4273 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4274 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004275 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4276 PATH_MAX, nls_codepage, remap);
Steve French737b7582005-04-28 22:41:06 -07004277 /* We can not add the asterik earlier in case
4278 it got remapped to 0xF03A as if it were part of the
4279 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004280 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07004281 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07004282 pSMB->FileName[name_len+1] = 0;
4283 pSMB->FileName[name_len+2] = '*';
4284 pSMB->FileName[name_len+3] = 0;
4285 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004286 pSMB->FileName[name_len] = 0; /* null terminate just in case */
4287 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07004288 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004289 } else { /* BB add check for overrun of SMB buf BB */
4290 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004291/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00004292 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004293 free buffer exit; BB */
4294 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07004295 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07004296 pSMB->FileName[name_len+1] = '*';
4297 pSMB->FileName[name_len+2] = 0;
4298 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004299 }
4300
4301 params = 12 + name_len /* includes null */ ;
4302 pSMB->TotalDataCount = 0; /* no EAs */
4303 pSMB->MaxParameterCount = cpu_to_le16(10);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004304 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004305 pSMB->MaxSetupCount = 0;
4306 pSMB->Reserved = 0;
4307 pSMB->Flags = 0;
4308 pSMB->Timeout = 0;
4309 pSMB->Reserved2 = 0;
4310 byte_count = params + 1 /* pad */ ;
4311 pSMB->TotalParameterCount = cpu_to_le16(params);
4312 pSMB->ParameterCount = pSMB->TotalParameterCount;
4313 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00004314 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
4315 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004316 pSMB->DataCount = 0;
4317 pSMB->DataOffset = 0;
4318 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
4319 pSMB->Reserved3 = 0;
4320 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
4321 pSMB->SearchAttributes =
4322 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
4323 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00004324 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004325 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004326 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4327
4328 /* BB what should we set StorageType to? Does it matter? BB */
4329 pSMB->SearchStorageType = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004330 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004331 pSMB->ByteCount = cpu_to_le16(byte_count);
4332
4333 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4334 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07004335 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004336
Steve French88274812006-03-09 22:21:45 +00004337 if (rc) {/* BB add logic to retry regular search if Unix search
4338 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004339 /* BB Add code to handle unsupported level rc */
Joe Perchesb6b38f72010-04-21 03:50:45 +00004340 cFYI(1, "Error in FindFirst = %d", rc);
Steve French1982c342005-08-17 12:38:22 -07004341
Steve French88274812006-03-09 22:21:45 +00004342 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004343
4344 /* BB eventually could optimize out free and realloc of buf */
4345 /* for this case */
4346 if (rc == -EAGAIN)
4347 goto findFirstRetry;
4348 } else { /* decode response */
4349 /* BB remember to free buffer if error BB */
4350 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00004351 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004352 unsigned int lnoff;
4353
Linus Torvalds1da177e2005-04-16 15:20:36 -07004354 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004355 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004356 else
Steve French4b18f2a2008-04-29 00:06:05 +00004357 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004358
4359 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004360 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00004361 psrch_inf->srch_entries_start =
4362 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004363 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004364 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
4365 le16_to_cpu(pSMBr->t2.ParameterOffset));
4366
Steve French790fe572007-07-07 19:25:05 +00004367 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004368 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004369 else
Steve French4b18f2a2008-04-29 00:06:05 +00004370 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004371
Steve French50c2f752007-07-13 00:33:32 +00004372 psrch_inf->entries_in_buffer =
4373 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00004374 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004375 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004376 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004377 if (CIFSMaxBufSize < lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004378 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00004379 psrch_inf->last_entry = NULL;
4380 return rc;
4381 }
4382
Steve French0752f152008-10-07 20:03:33 +00004383 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00004384 lnoff;
4385
Linus Torvalds1da177e2005-04-16 15:20:36 -07004386 *pnetfid = parms->SearchHandle;
4387 } else {
4388 cifs_buf_release(pSMB);
4389 }
4390 }
4391
4392 return rc;
4393}
4394
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004395int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
4396 __u16 searchHandle, __u16 search_flags,
4397 struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004398{
4399 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
4400 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004401 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004402 char *response_data;
4403 int rc = 0;
Jeff Layton9438fab2011-08-23 07:21:28 -04004404 int bytes_returned;
4405 unsigned int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004406 __u16 params, byte_count;
4407
Joe Perchesb6b38f72010-04-21 03:50:45 +00004408 cFYI(1, "In FindNext");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004409
Steve French4b18f2a2008-04-29 00:06:05 +00004410 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004411 return -ENOENT;
4412
4413 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4414 (void **) &pSMBr);
4415 if (rc)
4416 return rc;
4417
Steve French50c2f752007-07-13 00:33:32 +00004418 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004419 byte_count = 0;
4420 pSMB->TotalDataCount = 0; /* no EAs */
4421 pSMB->MaxParameterCount = cpu_to_le16(8);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004422 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004423 pSMB->MaxSetupCount = 0;
4424 pSMB->Reserved = 0;
4425 pSMB->Flags = 0;
4426 pSMB->Timeout = 0;
4427 pSMB->Reserved2 = 0;
4428 pSMB->ParameterOffset = cpu_to_le16(
4429 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
4430 pSMB->DataCount = 0;
4431 pSMB->DataOffset = 0;
4432 pSMB->SetupCount = 1;
4433 pSMB->Reserved3 = 0;
4434 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
4435 pSMB->SearchHandle = searchHandle; /* always kept as le */
4436 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00004437 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004438 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4439 pSMB->ResumeKey = psrch_inf->resume_key;
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004440 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004441
4442 name_len = psrch_inf->resume_name_len;
4443 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00004444 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004445 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
4446 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07004447 /* 14 byte parm len above enough for 2 byte null terminator */
4448 pSMB->ResumeFileName[name_len] = 0;
4449 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004450 } else {
4451 rc = -EINVAL;
4452 goto FNext2_err_exit;
4453 }
4454 byte_count = params + 1 /* pad */ ;
4455 pSMB->TotalParameterCount = cpu_to_le16(params);
4456 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004457 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004458 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004459
Linus Torvalds1da177e2005-04-16 15:20:36 -07004460 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4461 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07004462 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004463 if (rc) {
4464 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00004465 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07004466 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00004467 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004468 } else
Joe Perchesb6b38f72010-04-21 03:50:45 +00004469 cFYI(1, "FindNext returned = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004470 } else { /* decode response */
4471 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00004472
Steve French790fe572007-07-07 19:25:05 +00004473 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004474 unsigned int lnoff;
4475
Linus Torvalds1da177e2005-04-16 15:20:36 -07004476 /* BB fixme add lock for file (srch_info) struct here */
4477 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004478 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004479 else
Steve French4b18f2a2008-04-29 00:06:05 +00004480 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004481 response_data = (char *) &pSMBr->hdr.Protocol +
4482 le16_to_cpu(pSMBr->t2.ParameterOffset);
4483 parms = (T2_FNEXT_RSP_PARMS *)response_data;
4484 response_data = (char *)&pSMBr->hdr.Protocol +
4485 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00004486 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00004487 cifs_small_buf_release(
4488 psrch_inf->ntwrk_buf_start);
4489 else
4490 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004491 psrch_inf->srch_entries_start = response_data;
4492 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004493 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00004494 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004495 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004496 else
Steve French4b18f2a2008-04-29 00:06:05 +00004497 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00004498 psrch_inf->entries_in_buffer =
4499 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004500 psrch_inf->index_of_last_entry +=
4501 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004502 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004503 if (CIFSMaxBufSize < lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004504 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00004505 psrch_inf->last_entry = NULL;
4506 return rc;
4507 } else
4508 psrch_inf->last_entry =
4509 psrch_inf->srch_entries_start + lnoff;
4510
Joe Perchesb6b38f72010-04-21 03:50:45 +00004511/* cFYI(1, "fnxt2 entries in buf %d index_of_last %d",
4512 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004513
4514 /* BB fixme add unlock here */
4515 }
4516
4517 }
4518
4519 /* BB On error, should we leave previous search buf (and count and
4520 last entry fields) intact or free the previous one? */
4521
4522 /* Note: On -EAGAIN error only caller can retry on handle based calls
4523 since file handle passed in no longer valid */
4524FNext2_err_exit:
4525 if (rc != 0)
4526 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004527 return rc;
4528}
4529
4530int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004531CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004532 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004533{
4534 int rc = 0;
4535 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004536
Joe Perchesb6b38f72010-04-21 03:50:45 +00004537 cFYI(1, "In CIFSSMBFindClose");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004538 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
4539
4540 /* no sense returning error if session restarted
4541 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00004542 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004543 return 0;
4544 if (rc)
4545 return rc;
4546
Linus Torvalds1da177e2005-04-16 15:20:36 -07004547 pSMB->FileID = searchHandle;
4548 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04004549 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004550 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00004551 cERROR(1, "Send error in FindClose = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00004552
Steve Frencha4544342005-08-24 13:59:35 -07004553 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004554
4555 /* Since session is dead, search handle closed on server already */
4556 if (rc == -EAGAIN)
4557 rc = 0;
4558
4559 return rc;
4560}
4561
Linus Torvalds1da177e2005-04-16 15:20:36 -07004562int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004563CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004564 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00004565 __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00004566 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004567{
4568 int rc = 0;
4569 TRANSACTION2_QPI_REQ *pSMB = NULL;
4570 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4571 int name_len, bytes_returned;
4572 __u16 params, byte_count;
4573
Joe Perchesb6b38f72010-04-21 03:50:45 +00004574 cFYI(1, "In GetSrvInodeNum for %s", searchName);
Steve French790fe572007-07-07 19:25:05 +00004575 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00004576 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004577
4578GetInodeNumberRetry:
4579 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004580 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004581 if (rc)
4582 return rc;
4583
Linus Torvalds1da177e2005-04-16 15:20:36 -07004584 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4585 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004586 cifsConvertToUTF16((__le16 *) pSMB->FileName,
4587 searchName, PATH_MAX, nls_codepage,
4588 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004589 name_len++; /* trailing null */
4590 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004591 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004592 name_len = strnlen(searchName, PATH_MAX);
4593 name_len++; /* trailing null */
4594 strncpy(pSMB->FileName, searchName, name_len);
4595 }
4596
4597 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4598 pSMB->TotalDataCount = 0;
4599 pSMB->MaxParameterCount = cpu_to_le16(2);
4600 /* BB find exact max data count below from sess structure BB */
4601 pSMB->MaxDataCount = cpu_to_le16(4000);
4602 pSMB->MaxSetupCount = 0;
4603 pSMB->Reserved = 0;
4604 pSMB->Flags = 0;
4605 pSMB->Timeout = 0;
4606 pSMB->Reserved2 = 0;
4607 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004608 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004609 pSMB->DataCount = 0;
4610 pSMB->DataOffset = 0;
4611 pSMB->SetupCount = 1;
4612 pSMB->Reserved3 = 0;
4613 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4614 byte_count = params + 1 /* pad */ ;
4615 pSMB->TotalParameterCount = cpu_to_le16(params);
4616 pSMB->ParameterCount = pSMB->TotalParameterCount;
4617 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4618 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004619 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004620 pSMB->ByteCount = cpu_to_le16(byte_count);
4621
4622 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4623 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4624 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004625 cFYI(1, "error %d in QueryInternalInfo", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004626 } else {
4627 /* decode response */
4628 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004629 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04004630 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004631 /* If rc should we check for EOPNOSUPP and
4632 disable the srvino flag? or in caller? */
4633 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00004634 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004635 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4636 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00004637 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004638 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00004639 if (count < 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004640 cFYI(1, "Illegal size ret in QryIntrnlInf");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004641 rc = -EIO;
4642 goto GetInodeNumOut;
4643 }
4644 pfinfo = (struct file_internal_info *)
4645 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00004646 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004647 }
4648 }
4649GetInodeNumOut:
4650 cifs_buf_release(pSMB);
4651 if (rc == -EAGAIN)
4652 goto GetInodeNumberRetry;
4653 return rc;
4654}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004655
Igor Mammedovfec45852008-05-16 13:06:30 +04004656/* parses DFS refferal V3 structure
4657 * caller is responsible for freeing target_nodes
4658 * returns:
4659 * on success - 0
4660 * on failure - errno
4661 */
4662static int
Steve Frencha1fe78f2008-05-16 18:48:38 +00004663parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
Igor Mammedovfec45852008-05-16 13:06:30 +04004664 unsigned int *num_of_nodes,
4665 struct dfs_info3_param **target_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004666 const struct nls_table *nls_codepage, int remap,
4667 const char *searchName)
Igor Mammedovfec45852008-05-16 13:06:30 +04004668{
4669 int i, rc = 0;
4670 char *data_end;
4671 bool is_unicode;
4672 struct dfs_referral_level_3 *ref;
4673
Harvey Harrison5ca33c62008-07-23 17:45:58 -07004674 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4675 is_unicode = true;
4676 else
4677 is_unicode = false;
Igor Mammedovfec45852008-05-16 13:06:30 +04004678 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
4679
4680 if (*num_of_nodes < 1) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004681 cERROR(1, "num_referrals: must be at least > 0,"
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004682 "but we get num_referrals = %d", *num_of_nodes);
Igor Mammedovfec45852008-05-16 13:06:30 +04004683 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004684 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004685 }
4686
4687 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
Al Viro1d92cfd2008-06-02 10:59:02 +01004688 if (ref->VersionNumber != cpu_to_le16(3)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004689 cERROR(1, "Referrals of V%d version are not supported,"
4690 "should be V3", le16_to_cpu(ref->VersionNumber));
Igor Mammedovfec45852008-05-16 13:06:30 +04004691 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004692 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004693 }
4694
4695 /* get the upper boundary of the resp buffer */
4696 data_end = (char *)(&(pSMBr->PathConsumed)) +
4697 le16_to_cpu(pSMBr->t2.DataCount);
4698
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004699 cFYI(1, "num_referrals: %d dfs flags: 0x%x ...",
Igor Mammedovfec45852008-05-16 13:06:30 +04004700 *num_of_nodes,
Joe Perchesb6b38f72010-04-21 03:50:45 +00004701 le32_to_cpu(pSMBr->DFSFlags));
Igor Mammedovfec45852008-05-16 13:06:30 +04004702
4703 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
4704 *num_of_nodes, GFP_KERNEL);
4705 if (*target_nodes == NULL) {
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004706 cERROR(1, "Failed to allocate buffer for target_nodes");
Igor Mammedovfec45852008-05-16 13:06:30 +04004707 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004708 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004709 }
4710
Daniel Mack3ad2f3f2010-02-03 08:01:28 +08004711 /* collect necessary data from referrals */
Igor Mammedovfec45852008-05-16 13:06:30 +04004712 for (i = 0; i < *num_of_nodes; i++) {
4713 char *temp;
4714 int max_len;
4715 struct dfs_info3_param *node = (*target_nodes)+i;
4716
Steve French0e0d2cf2009-05-01 05:27:32 +00004717 node->flags = le32_to_cpu(pSMBr->DFSFlags);
Igor Mammedov2c556082008-10-23 13:58:42 +04004718 if (is_unicode) {
Jeff Layton331c3132008-12-17 06:31:53 -05004719 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4720 GFP_KERNEL);
Steve French2920ee22009-08-31 15:27:26 +00004721 if (tmp == NULL) {
4722 rc = -ENOMEM;
4723 goto parse_DFS_referrals_exit;
4724 }
Steve Frenchacbbb762012-01-18 22:32:33 -06004725 cifsConvertToUTF16((__le16 *) tmp, searchName,
4726 PATH_MAX, nls_codepage, remap);
4727 node->path_consumed = cifs_utf16_bytes(tmp,
Jeff Layton69f801f2009-04-30 06:46:32 -04004728 le16_to_cpu(pSMBr->PathConsumed),
Igor Mammedov2c556082008-10-23 13:58:42 +04004729 nls_codepage);
4730 kfree(tmp);
4731 } else
4732 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4733
Igor Mammedovfec45852008-05-16 13:06:30 +04004734 node->server_type = le16_to_cpu(ref->ServerType);
4735 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4736
4737 /* copy DfsPath */
4738 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4739 max_len = data_end - temp;
Steve Frenchacbbb762012-01-18 22:32:33 -06004740 node->path_name = cifs_strndup_from_utf16(temp, max_len,
4741 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004742 if (!node->path_name) {
4743 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004744 goto parse_DFS_referrals_exit;
Jeff Layton066ce682009-04-30 07:16:14 -04004745 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004746
4747 /* copy link target UNC */
4748 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4749 max_len = data_end - temp;
Steve Frenchacbbb762012-01-18 22:32:33 -06004750 node->node_name = cifs_strndup_from_utf16(temp, max_len,
4751 is_unicode, nls_codepage);
Stefan Metzmacherd8f27992012-05-04 00:19:28 +02004752 if (!node->node_name) {
Jeff Laytond8e2f532009-05-14 07:46:59 -04004753 rc = -ENOMEM;
Stefan Metzmacherd8f27992012-05-04 00:19:28 +02004754 goto parse_DFS_referrals_exit;
4755 }
4756
4757 ref++;
Igor Mammedovfec45852008-05-16 13:06:30 +04004758 }
4759
Steve Frencha1fe78f2008-05-16 18:48:38 +00004760parse_DFS_referrals_exit:
Igor Mammedovfec45852008-05-16 13:06:30 +04004761 if (rc) {
4762 free_dfs_info_array(*target_nodes, *num_of_nodes);
4763 *target_nodes = NULL;
4764 *num_of_nodes = 0;
4765 }
4766 return rc;
4767}
4768
Linus Torvalds1da177e2005-04-16 15:20:36 -07004769int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004770CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004771 const unsigned char *searchName,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004772 struct dfs_info3_param **target_nodes,
4773 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004774 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004775{
4776/* TRANS2_GET_DFS_REFERRAL */
4777 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4778 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004779 int rc = 0;
4780 int bytes_returned;
4781 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004782 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004783 *num_of_nodes = 0;
4784 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004785
Joe Perchesb6b38f72010-04-21 03:50:45 +00004786 cFYI(1, "In GetDFSRefer the path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004787 if (ses == NULL)
4788 return -ENODEV;
4789getDFSRetry:
4790 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4791 (void **) &pSMBr);
4792 if (rc)
4793 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004794
4795 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004796 but should never be null here anyway */
Pavel Shilovsky88257362012-05-23 14:01:59 +04004797 pSMB->hdr.Mid = get_next_mid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004798 pSMB->hdr.Tid = ses->ipc_tid;
4799 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004800 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004801 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004802 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004803 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004804
4805 if (ses->capabilities & CAP_UNICODE) {
4806 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4807 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004808 cifsConvertToUTF16((__le16 *) pSMB->RequestFileName,
4809 searchName, PATH_MAX, nls_codepage,
4810 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004811 name_len++; /* trailing null */
4812 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004813 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004814 name_len = strnlen(searchName, PATH_MAX);
4815 name_len++; /* trailing null */
4816 strncpy(pSMB->RequestFileName, searchName, name_len);
4817 }
4818
Steve French790fe572007-07-07 19:25:05 +00004819 if (ses->server) {
Steve French96daf2b2011-05-27 04:34:02 +00004820 if (ses->server->sec_mode &
Steve French1a4e15a2006-10-12 21:33:51 +00004821 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4822 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4823 }
4824
Steve French50c2f752007-07-13 00:33:32 +00004825 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004826
Linus Torvalds1da177e2005-04-16 15:20:36 -07004827 params = 2 /* level */ + name_len /*includes null */ ;
4828 pSMB->TotalDataCount = 0;
4829 pSMB->DataCount = 0;
4830 pSMB->DataOffset = 0;
4831 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004832 /* BB find exact max SMB PDU from sess structure BB */
4833 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004834 pSMB->MaxSetupCount = 0;
4835 pSMB->Reserved = 0;
4836 pSMB->Flags = 0;
4837 pSMB->Timeout = 0;
4838 pSMB->Reserved2 = 0;
4839 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004840 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004841 pSMB->SetupCount = 1;
4842 pSMB->Reserved3 = 0;
4843 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4844 byte_count = params + 3 /* pad */ ;
4845 pSMB->ParameterCount = cpu_to_le16(params);
4846 pSMB->TotalParameterCount = pSMB->ParameterCount;
4847 pSMB->MaxReferralLevel = cpu_to_le16(3);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004848 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004849 pSMB->ByteCount = cpu_to_le16(byte_count);
4850
4851 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4852 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4853 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004854 cFYI(1, "Send error in GetDFSRefer = %d", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004855 goto GetDFSRefExit;
4856 }
4857 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004858
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004859 /* BB Also check if enough total bytes returned? */
Jeff Layton820a8032011-05-04 08:05:26 -04004860 if (rc || get_bcc(&pSMBr->hdr) < 17) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004861 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004862 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004863 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004864
Joe Perchesb6b38f72010-04-21 03:50:45 +00004865 cFYI(1, "Decoding GetDFSRefer response BCC: %d Offset %d",
Jeff Layton820a8032011-05-04 08:05:26 -04004866 get_bcc(&pSMBr->hdr),
Joe Perchesb6b38f72010-04-21 03:50:45 +00004867 le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04004868
4869 /* parse returned result into more usable form */
Steve Frencha1fe78f2008-05-16 18:48:38 +00004870 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004871 target_nodes, nls_codepage, remap,
4872 searchName);
Igor Mammedovfec45852008-05-16 13:06:30 +04004873
Linus Torvalds1da177e2005-04-16 15:20:36 -07004874GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004875 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004876
4877 if (rc == -EAGAIN)
4878 goto getDFSRetry;
4879
4880 return rc;
4881}
4882
Steve French20962432005-09-21 22:05:57 -07004883/* Query File System Info such as free space to old servers such as Win 9x */
4884int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004885SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4886 struct kstatfs *FSData)
Steve French20962432005-09-21 22:05:57 -07004887{
4888/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4889 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4890 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4891 FILE_SYSTEM_ALLOC_INFO *response_data;
4892 int rc = 0;
4893 int bytes_returned = 0;
4894 __u16 params, byte_count;
4895
Joe Perchesb6b38f72010-04-21 03:50:45 +00004896 cFYI(1, "OldQFSInfo");
Steve French20962432005-09-21 22:05:57 -07004897oldQFSInfoRetry:
4898 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4899 (void **) &pSMBr);
4900 if (rc)
4901 return rc;
Steve French20962432005-09-21 22:05:57 -07004902
4903 params = 2; /* level */
4904 pSMB->TotalDataCount = 0;
4905 pSMB->MaxParameterCount = cpu_to_le16(2);
4906 pSMB->MaxDataCount = cpu_to_le16(1000);
4907 pSMB->MaxSetupCount = 0;
4908 pSMB->Reserved = 0;
4909 pSMB->Flags = 0;
4910 pSMB->Timeout = 0;
4911 pSMB->Reserved2 = 0;
4912 byte_count = params + 1 /* pad */ ;
4913 pSMB->TotalParameterCount = cpu_to_le16(params);
4914 pSMB->ParameterCount = pSMB->TotalParameterCount;
4915 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4916 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4917 pSMB->DataCount = 0;
4918 pSMB->DataOffset = 0;
4919 pSMB->SetupCount = 1;
4920 pSMB->Reserved3 = 0;
4921 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4922 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004923 inc_rfc1001_len(pSMB, byte_count);
Steve French20962432005-09-21 22:05:57 -07004924 pSMB->ByteCount = cpu_to_le16(byte_count);
4925
4926 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4927 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4928 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004929 cFYI(1, "Send error in QFSInfo = %d", rc);
Steve French20962432005-09-21 22:05:57 -07004930 } else { /* decode response */
4931 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4932
Jeff Layton820a8032011-05-04 08:05:26 -04004933 if (rc || get_bcc(&pSMBr->hdr) < 18)
Steve French20962432005-09-21 22:05:57 -07004934 rc = -EIO; /* bad smb */
4935 else {
4936 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004937 cFYI(1, "qfsinf resp BCC: %d Offset %d",
Jeff Layton820a8032011-05-04 08:05:26 -04004938 get_bcc(&pSMBr->hdr), data_offset);
Steve French20962432005-09-21 22:05:57 -07004939
Steve French50c2f752007-07-13 00:33:32 +00004940 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004941 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4942 FSData->f_bsize =
4943 le16_to_cpu(response_data->BytesPerSector) *
4944 le32_to_cpu(response_data->
4945 SectorsPerAllocationUnit);
4946 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004947 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004948 FSData->f_bfree = FSData->f_bavail =
4949 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004950 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
4951 (unsigned long long)FSData->f_blocks,
4952 (unsigned long long)FSData->f_bfree,
4953 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07004954 }
4955 }
4956 cifs_buf_release(pSMB);
4957
4958 if (rc == -EAGAIN)
4959 goto oldQFSInfoRetry;
4960
4961 return rc;
4962}
4963
Linus Torvalds1da177e2005-04-16 15:20:36 -07004964int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004965CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4966 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004967{
4968/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4969 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4970 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4971 FILE_SYSTEM_INFO *response_data;
4972 int rc = 0;
4973 int bytes_returned = 0;
4974 __u16 params, byte_count;
4975
Joe Perchesb6b38f72010-04-21 03:50:45 +00004976 cFYI(1, "In QFSInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004977QFSInfoRetry:
4978 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4979 (void **) &pSMBr);
4980 if (rc)
4981 return rc;
4982
4983 params = 2; /* level */
4984 pSMB->TotalDataCount = 0;
4985 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004986 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004987 pSMB->MaxSetupCount = 0;
4988 pSMB->Reserved = 0;
4989 pSMB->Flags = 0;
4990 pSMB->Timeout = 0;
4991 pSMB->Reserved2 = 0;
4992 byte_count = params + 1 /* pad */ ;
4993 pSMB->TotalParameterCount = cpu_to_le16(params);
4994 pSMB->ParameterCount = pSMB->TotalParameterCount;
4995 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004996 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004997 pSMB->DataCount = 0;
4998 pSMB->DataOffset = 0;
4999 pSMB->SetupCount = 1;
5000 pSMB->Reserved3 = 0;
5001 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5002 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005003 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005004 pSMB->ByteCount = cpu_to_le16(byte_count);
5005
5006 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5007 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5008 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005009 cFYI(1, "Send error in QFSInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005010 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00005011 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005012
Jeff Layton820a8032011-05-04 08:05:26 -04005013 if (rc || get_bcc(&pSMBr->hdr) < 24)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005014 rc = -EIO; /* bad smb */
5015 else {
5016 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005017
5018 response_data =
5019 (FILE_SYSTEM_INFO
5020 *) (((char *) &pSMBr->hdr.Protocol) +
5021 data_offset);
5022 FSData->f_bsize =
5023 le32_to_cpu(response_data->BytesPerSector) *
5024 le32_to_cpu(response_data->
5025 SectorsPerAllocationUnit);
5026 FSData->f_blocks =
5027 le64_to_cpu(response_data->TotalAllocationUnits);
5028 FSData->f_bfree = FSData->f_bavail =
5029 le64_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesb6b38f72010-04-21 03:50:45 +00005030 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
5031 (unsigned long long)FSData->f_blocks,
5032 (unsigned long long)FSData->f_bfree,
5033 FSData->f_bsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005034 }
5035 }
5036 cifs_buf_release(pSMB);
5037
5038 if (rc == -EAGAIN)
5039 goto QFSInfoRetry;
5040
5041 return rc;
5042}
5043
5044int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005045CIFSSMBQFSAttributeInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005046{
5047/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
5048 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5049 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5050 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
5051 int rc = 0;
5052 int bytes_returned = 0;
5053 __u16 params, byte_count;
5054
Joe Perchesb6b38f72010-04-21 03:50:45 +00005055 cFYI(1, "In QFSAttributeInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005056QFSAttributeRetry:
5057 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5058 (void **) &pSMBr);
5059 if (rc)
5060 return rc;
5061
5062 params = 2; /* level */
5063 pSMB->TotalDataCount = 0;
5064 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005065 /* BB find exact max SMB PDU from sess structure BB */
5066 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005067 pSMB->MaxSetupCount = 0;
5068 pSMB->Reserved = 0;
5069 pSMB->Flags = 0;
5070 pSMB->Timeout = 0;
5071 pSMB->Reserved2 = 0;
5072 byte_count = params + 1 /* pad */ ;
5073 pSMB->TotalParameterCount = cpu_to_le16(params);
5074 pSMB->ParameterCount = pSMB->TotalParameterCount;
5075 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005076 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005077 pSMB->DataCount = 0;
5078 pSMB->DataOffset = 0;
5079 pSMB->SetupCount = 1;
5080 pSMB->Reserved3 = 0;
5081 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5082 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005083 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005084 pSMB->ByteCount = cpu_to_le16(byte_count);
5085
5086 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5087 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5088 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005089 cERROR(1, "Send error in QFSAttributeInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005090 } else { /* decode response */
5091 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5092
Jeff Layton820a8032011-05-04 08:05:26 -04005093 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Steve French50c2f752007-07-13 00:33:32 +00005094 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005095 rc = -EIO; /* bad smb */
5096 } else {
5097 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5098 response_data =
5099 (FILE_SYSTEM_ATTRIBUTE_INFO
5100 *) (((char *) &pSMBr->hdr.Protocol) +
5101 data_offset);
5102 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005103 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005104 }
5105 }
5106 cifs_buf_release(pSMB);
5107
5108 if (rc == -EAGAIN)
5109 goto QFSAttributeRetry;
5110
5111 return rc;
5112}
5113
5114int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005115CIFSSMBQFSDeviceInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005116{
5117/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
5118 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5119 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5120 FILE_SYSTEM_DEVICE_INFO *response_data;
5121 int rc = 0;
5122 int bytes_returned = 0;
5123 __u16 params, byte_count;
5124
Joe Perchesb6b38f72010-04-21 03:50:45 +00005125 cFYI(1, "In QFSDeviceInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005126QFSDeviceRetry:
5127 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5128 (void **) &pSMBr);
5129 if (rc)
5130 return rc;
5131
5132 params = 2; /* level */
5133 pSMB->TotalDataCount = 0;
5134 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005135 /* BB find exact max SMB PDU from sess structure BB */
5136 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005137 pSMB->MaxSetupCount = 0;
5138 pSMB->Reserved = 0;
5139 pSMB->Flags = 0;
5140 pSMB->Timeout = 0;
5141 pSMB->Reserved2 = 0;
5142 byte_count = params + 1 /* pad */ ;
5143 pSMB->TotalParameterCount = cpu_to_le16(params);
5144 pSMB->ParameterCount = pSMB->TotalParameterCount;
5145 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005146 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005147
5148 pSMB->DataCount = 0;
5149 pSMB->DataOffset = 0;
5150 pSMB->SetupCount = 1;
5151 pSMB->Reserved3 = 0;
5152 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5153 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005154 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005155 pSMB->ByteCount = cpu_to_le16(byte_count);
5156
5157 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5158 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5159 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005160 cFYI(1, "Send error in QFSDeviceInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005161 } else { /* decode response */
5162 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5163
Jeff Layton820a8032011-05-04 08:05:26 -04005164 if (rc || get_bcc(&pSMBr->hdr) <
5165 sizeof(FILE_SYSTEM_DEVICE_INFO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005166 rc = -EIO; /* bad smb */
5167 else {
5168 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5169 response_data =
Steve French737b7582005-04-28 22:41:06 -07005170 (FILE_SYSTEM_DEVICE_INFO *)
5171 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07005172 data_offset);
5173 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005174 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005175 }
5176 }
5177 cifs_buf_release(pSMB);
5178
5179 if (rc == -EAGAIN)
5180 goto QFSDeviceRetry;
5181
5182 return rc;
5183}
5184
5185int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005186CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005187{
5188/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
5189 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5190 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5191 FILE_SYSTEM_UNIX_INFO *response_data;
5192 int rc = 0;
5193 int bytes_returned = 0;
5194 __u16 params, byte_count;
5195
Joe Perchesb6b38f72010-04-21 03:50:45 +00005196 cFYI(1, "In QFSUnixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005197QFSUnixRetry:
Jeff Laytonf5695992010-09-29 15:27:08 -04005198 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5199 (void **) &pSMB, (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005200 if (rc)
5201 return rc;
5202
5203 params = 2; /* level */
5204 pSMB->TotalDataCount = 0;
5205 pSMB->DataCount = 0;
5206 pSMB->DataOffset = 0;
5207 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005208 /* BB find exact max SMB PDU from sess structure BB */
5209 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005210 pSMB->MaxSetupCount = 0;
5211 pSMB->Reserved = 0;
5212 pSMB->Flags = 0;
5213 pSMB->Timeout = 0;
5214 pSMB->Reserved2 = 0;
5215 byte_count = params + 1 /* pad */ ;
5216 pSMB->ParameterCount = cpu_to_le16(params);
5217 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005218 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5219 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005220 pSMB->SetupCount = 1;
5221 pSMB->Reserved3 = 0;
5222 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5223 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005224 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005225 pSMB->ByteCount = cpu_to_le16(byte_count);
5226
5227 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5228 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5229 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005230 cERROR(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005231 } else { /* decode response */
5232 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5233
Jeff Layton820a8032011-05-04 08:05:26 -04005234 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005235 rc = -EIO; /* bad smb */
5236 } else {
5237 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5238 response_data =
5239 (FILE_SYSTEM_UNIX_INFO
5240 *) (((char *) &pSMBr->hdr.Protocol) +
5241 data_offset);
5242 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005243 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005244 }
5245 }
5246 cifs_buf_release(pSMB);
5247
5248 if (rc == -EAGAIN)
5249 goto QFSUnixRetry;
5250
5251
5252 return rc;
5253}
5254
Jeremy Allisonac670552005-06-22 17:26:35 -07005255int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005256CIFSSMBSetFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07005257{
5258/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
5259 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
5260 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
5261 int rc = 0;
5262 int bytes_returned = 0;
5263 __u16 params, param_offset, offset, byte_count;
5264
Joe Perchesb6b38f72010-04-21 03:50:45 +00005265 cFYI(1, "In SETFSUnixInfo");
Jeremy Allisonac670552005-06-22 17:26:35 -07005266SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00005267 /* BB switch to small buf init to save memory */
Jeff Laytonf5695992010-09-29 15:27:08 -04005268 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5269 (void **) &pSMB, (void **) &pSMBr);
Jeremy Allisonac670552005-06-22 17:26:35 -07005270 if (rc)
5271 return rc;
5272
5273 params = 4; /* 2 bytes zero followed by info level. */
5274 pSMB->MaxSetupCount = 0;
5275 pSMB->Reserved = 0;
5276 pSMB->Flags = 0;
5277 pSMB->Timeout = 0;
5278 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00005279 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
5280 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07005281 offset = param_offset + params;
5282
5283 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00005284 /* BB find exact max SMB PDU from sess structure BB */
5285 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07005286 pSMB->SetupCount = 1;
5287 pSMB->Reserved3 = 0;
5288 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
5289 byte_count = 1 /* pad */ + params + 12;
5290
5291 pSMB->DataCount = cpu_to_le16(12);
5292 pSMB->ParameterCount = cpu_to_le16(params);
5293 pSMB->TotalDataCount = pSMB->DataCount;
5294 pSMB->TotalParameterCount = pSMB->ParameterCount;
5295 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5296 pSMB->DataOffset = cpu_to_le16(offset);
5297
5298 /* Params. */
5299 pSMB->FileNum = 0;
5300 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
5301
5302 /* Data. */
5303 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
5304 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
5305 pSMB->ClientUnixCap = cpu_to_le64(cap);
5306
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005307 inc_rfc1001_len(pSMB, byte_count);
Jeremy Allisonac670552005-06-22 17:26:35 -07005308 pSMB->ByteCount = cpu_to_le16(byte_count);
5309
5310 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5311 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5312 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005313 cERROR(1, "Send error in SETFSUnixInfo = %d", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07005314 } else { /* decode response */
5315 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00005316 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07005317 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07005318 }
5319 cifs_buf_release(pSMB);
5320
5321 if (rc == -EAGAIN)
5322 goto SETFSUnixRetry;
5323
5324 return rc;
5325}
5326
5327
Linus Torvalds1da177e2005-04-16 15:20:36 -07005328
5329int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005330CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon,
Steve French737b7582005-04-28 22:41:06 -07005331 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005332{
5333/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
5334 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5335 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5336 FILE_SYSTEM_POSIX_INFO *response_data;
5337 int rc = 0;
5338 int bytes_returned = 0;
5339 __u16 params, byte_count;
5340
Joe Perchesb6b38f72010-04-21 03:50:45 +00005341 cFYI(1, "In QFSPosixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005342QFSPosixRetry:
5343 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5344 (void **) &pSMBr);
5345 if (rc)
5346 return rc;
5347
5348 params = 2; /* level */
5349 pSMB->TotalDataCount = 0;
5350 pSMB->DataCount = 0;
5351 pSMB->DataOffset = 0;
5352 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005353 /* BB find exact max SMB PDU from sess structure BB */
5354 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005355 pSMB->MaxSetupCount = 0;
5356 pSMB->Reserved = 0;
5357 pSMB->Flags = 0;
5358 pSMB->Timeout = 0;
5359 pSMB->Reserved2 = 0;
5360 byte_count = params + 1 /* pad */ ;
5361 pSMB->ParameterCount = cpu_to_le16(params);
5362 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005363 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5364 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005365 pSMB->SetupCount = 1;
5366 pSMB->Reserved3 = 0;
5367 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5368 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005369 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005370 pSMB->ByteCount = cpu_to_le16(byte_count);
5371
5372 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5373 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5374 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005375 cFYI(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005376 } else { /* decode response */
5377 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5378
Jeff Layton820a8032011-05-04 08:05:26 -04005379 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005380 rc = -EIO; /* bad smb */
5381 } else {
5382 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5383 response_data =
5384 (FILE_SYSTEM_POSIX_INFO
5385 *) (((char *) &pSMBr->hdr.Protocol) +
5386 data_offset);
5387 FSData->f_bsize =
5388 le32_to_cpu(response_data->BlockSize);
5389 FSData->f_blocks =
5390 le64_to_cpu(response_data->TotalBlocks);
5391 FSData->f_bfree =
5392 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00005393 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005394 FSData->f_bavail = FSData->f_bfree;
5395 } else {
5396 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00005397 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005398 }
Steve French790fe572007-07-07 19:25:05 +00005399 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005400 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00005401 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00005402 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005403 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00005404 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005405 }
5406 }
5407 cifs_buf_release(pSMB);
5408
5409 if (rc == -EAGAIN)
5410 goto QFSPosixRetry;
5411
5412 return rc;
5413}
5414
5415
Steve French50c2f752007-07-13 00:33:32 +00005416/* We can not use write of zero bytes trick to
5417 set file size due to need for large file support. Also note that
5418 this SetPathInfo is preferred to SetFileInfo based method in next
Linus Torvalds1da177e2005-04-16 15:20:36 -07005419 routine which is only needed to work around a sharing violation bug
5420 in Samba which this routine can run into */
5421
5422int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005423CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
5424 const char *fileName, __u64 size, bool SetAllocation,
Steve French737b7582005-04-28 22:41:06 -07005425 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005426{
5427 struct smb_com_transaction2_spi_req *pSMB = NULL;
5428 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5429 struct file_end_of_file_info *parm_data;
5430 int name_len;
5431 int rc = 0;
5432 int bytes_returned = 0;
5433 __u16 params, byte_count, data_count, param_offset, offset;
5434
Joe Perchesb6b38f72010-04-21 03:50:45 +00005435 cFYI(1, "In SetEOF");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005436SetEOFRetry:
5437 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5438 (void **) &pSMBr);
5439 if (rc)
5440 return rc;
5441
5442 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5443 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005444 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5445 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005446 name_len++; /* trailing null */
5447 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005448 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005449 name_len = strnlen(fileName, PATH_MAX);
5450 name_len++; /* trailing null */
5451 strncpy(pSMB->FileName, fileName, name_len);
5452 }
5453 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005454 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005455 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07005456 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005457 pSMB->MaxSetupCount = 0;
5458 pSMB->Reserved = 0;
5459 pSMB->Flags = 0;
5460 pSMB->Timeout = 0;
5461 pSMB->Reserved2 = 0;
5462 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005463 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005464 offset = param_offset + params;
Steve French790fe572007-07-07 19:25:05 +00005465 if (SetAllocation) {
Steve French50c2f752007-07-13 00:33:32 +00005466 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5467 pSMB->InformationLevel =
5468 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5469 else
5470 pSMB->InformationLevel =
5471 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5472 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005473 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5474 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005475 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005476 else
5477 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005478 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005479 }
5480
5481 parm_data =
5482 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
5483 offset);
5484 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5485 pSMB->DataOffset = cpu_to_le16(offset);
5486 pSMB->SetupCount = 1;
5487 pSMB->Reserved3 = 0;
5488 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5489 byte_count = 3 /* pad */ + params + data_count;
5490 pSMB->DataCount = cpu_to_le16(data_count);
5491 pSMB->TotalDataCount = pSMB->DataCount;
5492 pSMB->ParameterCount = cpu_to_le16(params);
5493 pSMB->TotalParameterCount = pSMB->ParameterCount;
5494 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005495 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005496 parm_data->FileSize = cpu_to_le64(size);
5497 pSMB->ByteCount = cpu_to_le16(byte_count);
5498 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5499 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005500 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005501 cFYI(1, "SetPathInfo (file size) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005502
5503 cifs_buf_release(pSMB);
5504
5505 if (rc == -EAGAIN)
5506 goto SetEOFRetry;
5507
5508 return rc;
5509}
5510
5511int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005512CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon, __u64 size,
Steve French4b18f2a2008-04-29 00:06:05 +00005513 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005514{
5515 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005516 struct file_end_of_file_info *parm_data;
5517 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005518 __u16 params, param_offset, offset, byte_count, count;
5519
Joe Perchesb6b38f72010-04-21 03:50:45 +00005520 cFYI(1, "SetFileSize (via SetFileInfo) %lld",
5521 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07005522 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5523
Linus Torvalds1da177e2005-04-16 15:20:36 -07005524 if (rc)
5525 return rc;
5526
5527 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5528 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005529
Linus Torvalds1da177e2005-04-16 15:20:36 -07005530 params = 6;
5531 pSMB->MaxSetupCount = 0;
5532 pSMB->Reserved = 0;
5533 pSMB->Flags = 0;
5534 pSMB->Timeout = 0;
5535 pSMB->Reserved2 = 0;
5536 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5537 offset = param_offset + params;
5538
Linus Torvalds1da177e2005-04-16 15:20:36 -07005539 count = sizeof(struct file_end_of_file_info);
5540 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005541 /* BB find exact max SMB PDU from sess structure BB */
5542 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005543 pSMB->SetupCount = 1;
5544 pSMB->Reserved3 = 0;
5545 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5546 byte_count = 3 /* pad */ + params + count;
5547 pSMB->DataCount = cpu_to_le16(count);
5548 pSMB->ParameterCount = cpu_to_le16(params);
5549 pSMB->TotalDataCount = pSMB->DataCount;
5550 pSMB->TotalParameterCount = pSMB->ParameterCount;
5551 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5552 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00005553 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
5554 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005555 pSMB->DataOffset = cpu_to_le16(offset);
5556 parm_data->FileSize = cpu_to_le64(size);
5557 pSMB->Fid = fid;
Steve French790fe572007-07-07 19:25:05 +00005558 if (SetAllocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005559 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5560 pSMB->InformationLevel =
5561 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5562 else
5563 pSMB->InformationLevel =
5564 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00005565 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005566 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5567 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005568 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005569 else
5570 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005571 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005572 }
5573 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005574 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005575 pSMB->ByteCount = cpu_to_le16(byte_count);
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005576 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005577 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005578 cFYI(1, "Send error in SetFileInfo (SetFileSize) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005579 }
5580
Steve French50c2f752007-07-13 00:33:32 +00005581 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005582 since file handle passed in no longer valid */
5583
5584 return rc;
5585}
5586
Steve French50c2f752007-07-13 00:33:32 +00005587/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07005588 an open handle, rather than by pathname - this is awkward due to
5589 potential access conflicts on the open, but it is unavoidable for these
5590 old servers since the only other choice is to go from 100 nanosecond DCE
5591 time and resort to the original setpathinfo level which takes the ancient
5592 DOS time format with 2 second granularity */
5593int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005594CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005595 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005596{
5597 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005598 char *data_offset;
5599 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005600 __u16 params, param_offset, offset, byte_count, count;
5601
Joe Perchesb6b38f72010-04-21 03:50:45 +00005602 cFYI(1, "Set Times (via SetFileInfo)");
Steve Frenchcd634992005-04-28 22:41:10 -07005603 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5604
Linus Torvalds1da177e2005-04-16 15:20:36 -07005605 if (rc)
5606 return rc;
5607
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005608 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5609 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005610
Linus Torvalds1da177e2005-04-16 15:20:36 -07005611 params = 6;
5612 pSMB->MaxSetupCount = 0;
5613 pSMB->Reserved = 0;
5614 pSMB->Flags = 0;
5615 pSMB->Timeout = 0;
5616 pSMB->Reserved2 = 0;
5617 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5618 offset = param_offset + params;
5619
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005620 data_offset = (char *)pSMB +
5621 offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005622
Steve French26f57362007-08-30 22:09:15 +00005623 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005624 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005625 /* BB find max SMB PDU from sess */
5626 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005627 pSMB->SetupCount = 1;
5628 pSMB->Reserved3 = 0;
5629 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5630 byte_count = 3 /* pad */ + params + count;
5631 pSMB->DataCount = cpu_to_le16(count);
5632 pSMB->ParameterCount = cpu_to_le16(params);
5633 pSMB->TotalDataCount = pSMB->DataCount;
5634 pSMB->TotalParameterCount = pSMB->ParameterCount;
5635 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5636 pSMB->DataOffset = cpu_to_le16(offset);
5637 pSMB->Fid = fid;
5638 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5639 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5640 else
5641 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5642 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005643 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005644 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005645 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005646 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005647 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005648 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005649
Steve French50c2f752007-07-13 00:33:32 +00005650 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005651 since file handle passed in no longer valid */
5652
5653 return rc;
5654}
5655
Jeff Layton6d22f092008-09-23 11:48:35 -04005656int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005657CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6d22f092008-09-23 11:48:35 -04005658 bool delete_file, __u16 fid, __u32 pid_of_opener)
5659{
5660 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5661 char *data_offset;
5662 int rc = 0;
5663 __u16 params, param_offset, offset, byte_count, count;
5664
Joe Perchesb6b38f72010-04-21 03:50:45 +00005665 cFYI(1, "Set File Disposition (via SetFileInfo)");
Jeff Layton6d22f092008-09-23 11:48:35 -04005666 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5667
5668 if (rc)
5669 return rc;
5670
5671 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5672 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5673
5674 params = 6;
5675 pSMB->MaxSetupCount = 0;
5676 pSMB->Reserved = 0;
5677 pSMB->Flags = 0;
5678 pSMB->Timeout = 0;
5679 pSMB->Reserved2 = 0;
5680 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5681 offset = param_offset + params;
5682
5683 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5684
5685 count = 1;
5686 pSMB->MaxParameterCount = cpu_to_le16(2);
5687 /* BB find max SMB PDU from sess */
5688 pSMB->MaxDataCount = cpu_to_le16(1000);
5689 pSMB->SetupCount = 1;
5690 pSMB->Reserved3 = 0;
5691 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5692 byte_count = 3 /* pad */ + params + count;
5693 pSMB->DataCount = cpu_to_le16(count);
5694 pSMB->ParameterCount = cpu_to_le16(params);
5695 pSMB->TotalDataCount = pSMB->DataCount;
5696 pSMB->TotalParameterCount = pSMB->ParameterCount;
5697 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5698 pSMB->DataOffset = cpu_to_le16(offset);
5699 pSMB->Fid = fid;
5700 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5701 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005702 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton6d22f092008-09-23 11:48:35 -04005703 pSMB->ByteCount = cpu_to_le16(byte_count);
5704 *data_offset = delete_file ? 1 : 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005705 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Jeff Layton6d22f092008-09-23 11:48:35 -04005706 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005707 cFYI(1, "Send error in SetFileDisposition = %d", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005708
5709 return rc;
5710}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005711
5712int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005713CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6fc000e2008-08-02 07:26:12 -04005714 const char *fileName, const FILE_BASIC_INFO *data,
5715 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005716{
5717 TRANSACTION2_SPI_REQ *pSMB = NULL;
5718 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5719 int name_len;
5720 int rc = 0;
5721 int bytes_returned = 0;
5722 char *data_offset;
5723 __u16 params, param_offset, offset, byte_count, count;
5724
Joe Perchesb6b38f72010-04-21 03:50:45 +00005725 cFYI(1, "In SetTimes");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005726
5727SetTimesRetry:
5728 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5729 (void **) &pSMBr);
5730 if (rc)
5731 return rc;
5732
5733 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5734 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005735 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5736 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005737 name_len++; /* trailing null */
5738 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005739 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005740 name_len = strnlen(fileName, PATH_MAX);
5741 name_len++; /* trailing null */
5742 strncpy(pSMB->FileName, fileName, name_len);
5743 }
5744
5745 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005746 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005747 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005748 /* BB find max SMB PDU from sess structure BB */
5749 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005750 pSMB->MaxSetupCount = 0;
5751 pSMB->Reserved = 0;
5752 pSMB->Flags = 0;
5753 pSMB->Timeout = 0;
5754 pSMB->Reserved2 = 0;
5755 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005756 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005757 offset = param_offset + params;
5758 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5759 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5760 pSMB->DataOffset = cpu_to_le16(offset);
5761 pSMB->SetupCount = 1;
5762 pSMB->Reserved3 = 0;
5763 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5764 byte_count = 3 /* pad */ + params + count;
5765
5766 pSMB->DataCount = cpu_to_le16(count);
5767 pSMB->ParameterCount = cpu_to_le16(params);
5768 pSMB->TotalDataCount = pSMB->DataCount;
5769 pSMB->TotalParameterCount = pSMB->ParameterCount;
5770 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5771 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5772 else
5773 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5774 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005775 inc_rfc1001_len(pSMB, byte_count);
Steve French26f57362007-08-30 22:09:15 +00005776 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005777 pSMB->ByteCount = cpu_to_le16(byte_count);
5778 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5779 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005780 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005781 cFYI(1, "SetPathInfo (times) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005782
5783 cifs_buf_release(pSMB);
5784
5785 if (rc == -EAGAIN)
5786 goto SetTimesRetry;
5787
5788 return rc;
5789}
5790
5791/* Can not be used to set time stamps yet (due to old DOS time format) */
5792/* Can be used to set attributes */
5793#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5794 handling it anyway and NT4 was what we thought it would be needed for
5795 Do not delete it until we prove whether needed for Win9x though */
5796int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005797CIFSSMBSetAttrLegacy(unsigned int xid, struct cifs_tcon *tcon, char *fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005798 __u16 dos_attrs, const struct nls_table *nls_codepage)
5799{
5800 SETATTR_REQ *pSMB = NULL;
5801 SETATTR_RSP *pSMBr = NULL;
5802 int rc = 0;
5803 int bytes_returned;
5804 int name_len;
5805
Joe Perchesb6b38f72010-04-21 03:50:45 +00005806 cFYI(1, "In SetAttrLegacy");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005807
5808SetAttrLgcyRetry:
5809 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5810 (void **) &pSMBr);
5811 if (rc)
5812 return rc;
5813
5814 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5815 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005816 ConvertToUTF16((__le16 *) pSMB->fileName, fileName,
5817 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005818 name_len++; /* trailing null */
5819 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005820 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005821 name_len = strnlen(fileName, PATH_MAX);
5822 name_len++; /* trailing null */
5823 strncpy(pSMB->fileName, fileName, name_len);
5824 }
5825 pSMB->attr = cpu_to_le16(dos_attrs);
5826 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005827 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005828 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5829 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5830 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005831 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005832 cFYI(1, "Error in LegacySetAttr = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005833
5834 cifs_buf_release(pSMB);
5835
5836 if (rc == -EAGAIN)
5837 goto SetAttrLgcyRetry;
5838
5839 return rc;
5840}
5841#endif /* temporarily unneeded SetAttr legacy function */
5842
Jeff Layton654cf142009-07-09 20:02:49 -04005843static void
5844cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5845 const struct cifs_unix_set_info_args *args)
5846{
5847 u64 mode = args->mode;
5848
5849 /*
5850 * Samba server ignores set of file size to zero due to bugs in some
5851 * older clients, but we should be precise - we use SetFileSize to
5852 * set file size and do not want to truncate file size to zero
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005853 * accidentally as happened on one Samba server beta by putting
Jeff Layton654cf142009-07-09 20:02:49 -04005854 * zero instead of -1 here
5855 */
5856 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5857 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5858 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5859 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5860 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5861 data_offset->Uid = cpu_to_le64(args->uid);
5862 data_offset->Gid = cpu_to_le64(args->gid);
5863 /* better to leave device as zero when it is */
5864 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5865 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5866 data_offset->Permissions = cpu_to_le64(mode);
5867
5868 if (S_ISREG(mode))
5869 data_offset->Type = cpu_to_le32(UNIX_FILE);
5870 else if (S_ISDIR(mode))
5871 data_offset->Type = cpu_to_le32(UNIX_DIR);
5872 else if (S_ISLNK(mode))
5873 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5874 else if (S_ISCHR(mode))
5875 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5876 else if (S_ISBLK(mode))
5877 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5878 else if (S_ISFIFO(mode))
5879 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5880 else if (S_ISSOCK(mode))
5881 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5882}
5883
Linus Torvalds1da177e2005-04-16 15:20:36 -07005884int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005885CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005886 const struct cifs_unix_set_info_args *args,
5887 u16 fid, u32 pid_of_opener)
5888{
5889 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005890 char *data_offset;
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005891 int rc = 0;
5892 u16 params, param_offset, offset, byte_count, count;
5893
Joe Perchesb6b38f72010-04-21 03:50:45 +00005894 cFYI(1, "Set Unix Info (via SetFileInfo)");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005895 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5896
5897 if (rc)
5898 return rc;
5899
5900 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5901 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5902
5903 params = 6;
5904 pSMB->MaxSetupCount = 0;
5905 pSMB->Reserved = 0;
5906 pSMB->Flags = 0;
5907 pSMB->Timeout = 0;
5908 pSMB->Reserved2 = 0;
5909 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5910 offset = param_offset + params;
5911
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005912 data_offset = (char *)pSMB +
5913 offsetof(struct smb_hdr, Protocol) + offset;
5914
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005915 count = sizeof(FILE_UNIX_BASIC_INFO);
5916
5917 pSMB->MaxParameterCount = cpu_to_le16(2);
5918 /* BB find max SMB PDU from sess */
5919 pSMB->MaxDataCount = cpu_to_le16(1000);
5920 pSMB->SetupCount = 1;
5921 pSMB->Reserved3 = 0;
5922 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5923 byte_count = 3 /* pad */ + params + count;
5924 pSMB->DataCount = cpu_to_le16(count);
5925 pSMB->ParameterCount = cpu_to_le16(params);
5926 pSMB->TotalDataCount = pSMB->DataCount;
5927 pSMB->TotalParameterCount = pSMB->ParameterCount;
5928 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5929 pSMB->DataOffset = cpu_to_le16(offset);
5930 pSMB->Fid = fid;
5931 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5932 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005933 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005934 pSMB->ByteCount = cpu_to_le16(byte_count);
5935
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005936 cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005937
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005938 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005939 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005940 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005941
5942 /* Note: On -EAGAIN error only caller can retry on handle based calls
5943 since file handle passed in no longer valid */
5944
5945 return rc;
5946}
5947
5948int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005949CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
5950 char *fileName,
Jeff Layton01ea95e2009-07-09 20:02:49 -04005951 const struct cifs_unix_set_info_args *args,
5952 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005953{
5954 TRANSACTION2_SPI_REQ *pSMB = NULL;
5955 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5956 int name_len;
5957 int rc = 0;
5958 int bytes_returned = 0;
5959 FILE_UNIX_BASIC_INFO *data_offset;
5960 __u16 params, param_offset, offset, count, byte_count;
5961
Joe Perchesb6b38f72010-04-21 03:50:45 +00005962 cFYI(1, "In SetUID/GID/Mode");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005963setPermsRetry:
5964 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5965 (void **) &pSMBr);
5966 if (rc)
5967 return rc;
5968
5969 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5970 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005971 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5972 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005973 name_len++; /* trailing null */
5974 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005975 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005976 name_len = strnlen(fileName, PATH_MAX);
5977 name_len++; /* trailing null */
5978 strncpy(pSMB->FileName, fileName, name_len);
5979 }
5980
5981 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005982 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005983 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005984 /* BB find max SMB PDU from sess structure BB */
5985 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005986 pSMB->MaxSetupCount = 0;
5987 pSMB->Reserved = 0;
5988 pSMB->Flags = 0;
5989 pSMB->Timeout = 0;
5990 pSMB->Reserved2 = 0;
5991 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005992 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005993 offset = param_offset + params;
5994 data_offset =
5995 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5996 offset);
5997 memset(data_offset, 0, count);
5998 pSMB->DataOffset = cpu_to_le16(offset);
5999 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6000 pSMB->SetupCount = 1;
6001 pSMB->Reserved3 = 0;
6002 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6003 byte_count = 3 /* pad */ + params + count;
6004 pSMB->ParameterCount = cpu_to_le16(params);
6005 pSMB->DataCount = cpu_to_le16(count);
6006 pSMB->TotalParameterCount = pSMB->ParameterCount;
6007 pSMB->TotalDataCount = pSMB->DataCount;
6008 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6009 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006010 inc_rfc1001_len(pSMB, byte_count);
Steve French50c2f752007-07-13 00:33:32 +00006011
Jeff Layton654cf142009-07-09 20:02:49 -04006012 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006013
6014 pSMB->ByteCount = cpu_to_le16(byte_count);
6015 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6016 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006017 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00006018 cFYI(1, "SetPathInfo (perms) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006019
Steve French0d817bc2008-05-22 02:02:03 +00006020 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006021 if (rc == -EAGAIN)
6022 goto setPermsRetry;
6023 return rc;
6024}
6025
Linus Torvalds1da177e2005-04-16 15:20:36 -07006026#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05006027/*
6028 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
6029 * function used by listxattr and getxattr type calls. When ea_name is set,
6030 * it looks for that attribute name and stuffs that value into the EAData
6031 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
6032 * buffer. In both cases, the return value is either the length of the
6033 * resulting data or a negative error code. If EAData is a NULL pointer then
6034 * the data isn't copied to it, but the length is returned.
6035 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006036ssize_t
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006037CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05006038 const unsigned char *searchName, const unsigned char *ea_name,
6039 char *EAData, size_t buf_size,
6040 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006041{
6042 /* BB assumes one setup word */
6043 TRANSACTION2_QPI_REQ *pSMB = NULL;
6044 TRANSACTION2_QPI_RSP *pSMBr = NULL;
6045 int rc = 0;
6046 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05006047 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006048 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00006049 struct fea *temp_fea;
6050 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006051 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006052 __u16 params, byte_count, data_offset;
Jeff Layton5980fc92011-07-28 12:48:26 -04006053 unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006054
Joe Perchesb6b38f72010-04-21 03:50:45 +00006055 cFYI(1, "In Query All EAs path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006056QAllEAsRetry:
6057 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6058 (void **) &pSMBr);
6059 if (rc)
6060 return rc;
6061
6062 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05006063 list_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006064 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
6065 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05006066 list_len++; /* trailing null */
6067 list_len *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006068 } else { /* BB improve the check for buffer overruns BB */
Jeff Layton6e462b92010-02-10 16:18:26 -05006069 list_len = strnlen(searchName, PATH_MAX);
6070 list_len++; /* trailing null */
6071 strncpy(pSMB->FileName, searchName, list_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006072 }
6073
Jeff Layton6e462b92010-02-10 16:18:26 -05006074 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006075 pSMB->TotalDataCount = 0;
6076 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006077 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05006078 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006079 pSMB->MaxSetupCount = 0;
6080 pSMB->Reserved = 0;
6081 pSMB->Flags = 0;
6082 pSMB->Timeout = 0;
6083 pSMB->Reserved2 = 0;
6084 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00006085 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006086 pSMB->DataCount = 0;
6087 pSMB->DataOffset = 0;
6088 pSMB->SetupCount = 1;
6089 pSMB->Reserved3 = 0;
6090 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
6091 byte_count = params + 1 /* pad */ ;
6092 pSMB->TotalParameterCount = cpu_to_le16(params);
6093 pSMB->ParameterCount = pSMB->TotalParameterCount;
6094 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
6095 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006096 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006097 pSMB->ByteCount = cpu_to_le16(byte_count);
6098
6099 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6100 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6101 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006102 cFYI(1, "Send error in QueryAllEAs = %d", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05006103 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006104 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006105
6106
6107 /* BB also check enough total bytes returned */
6108 /* BB we need to improve the validity checking
6109 of these trans2 responses */
6110
6111 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Jeff Layton820a8032011-05-04 08:05:26 -04006112 if (rc || get_bcc(&pSMBr->hdr) < 4) {
Jeff Laytonf0d38682010-02-10 16:18:26 -05006113 rc = -EIO; /* bad smb */
6114 goto QAllEAsOut;
6115 }
6116
6117 /* check that length of list is not more than bcc */
6118 /* check that each entry does not go beyond length
6119 of list */
6120 /* check that each element of each entry does not
6121 go beyond end of list */
6122 /* validate_trans2_offsets() */
6123 /* BB check if start of smb + data_offset > &bcc+ bcc */
6124
6125 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
6126 ea_response_data = (struct fealist *)
6127 (((char *) &pSMBr->hdr.Protocol) + data_offset);
6128
Jeff Layton6e462b92010-02-10 16:18:26 -05006129 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesb6b38f72010-04-21 03:50:45 +00006130 cFYI(1, "ea length %d", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05006131 if (list_len <= 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006132 cFYI(1, "empty EA list returned from server");
Jeff Laytonf0d38682010-02-10 16:18:26 -05006133 goto QAllEAsOut;
6134 }
6135
Jeff Layton0cd126b2010-02-10 16:18:26 -05006136 /* make sure list_len doesn't go past end of SMB */
Jeff Layton690c5222011-01-20 13:36:51 -05006137 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
Jeff Layton0cd126b2010-02-10 16:18:26 -05006138 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006139 cFYI(1, "EA list appears to go beyond SMB");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006140 rc = -EIO;
6141 goto QAllEAsOut;
6142 }
6143
Jeff Laytonf0d38682010-02-10 16:18:26 -05006144 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05006145 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006146 temp_fea = ea_response_data->list;
6147 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05006148 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00006149 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006150 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006151
Jeff Layton6e462b92010-02-10 16:18:26 -05006152 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006153 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006154 /* make sure we can read name_len and value_len */
6155 if (list_len < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006156 cFYI(1, "EA entry goes beyond length of list");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006157 rc = -EIO;
6158 goto QAllEAsOut;
6159 }
6160
6161 name_len = temp_fea->name_len;
6162 value_len = le16_to_cpu(temp_fea->value_len);
6163 list_len -= name_len + 1 + value_len;
6164 if (list_len < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006165 cFYI(1, "EA entry goes beyond length of list");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006166 rc = -EIO;
6167 goto QAllEAsOut;
6168 }
6169
Jeff Layton31c05192010-02-10 16:18:26 -05006170 if (ea_name) {
Jeff Layton91d065c2011-07-26 18:23:47 -04006171 if (ea_name_len == name_len &&
Jeff Laytonac423442011-10-11 06:41:32 -04006172 memcmp(ea_name, temp_ptr, name_len) == 0) {
Jeff Layton31c05192010-02-10 16:18:26 -05006173 temp_ptr += name_len + 1;
6174 rc = value_len;
6175 if (buf_size == 0)
6176 goto QAllEAsOut;
6177 if ((size_t)value_len > buf_size) {
6178 rc = -ERANGE;
6179 goto QAllEAsOut;
6180 }
6181 memcpy(EAData, temp_ptr, value_len);
6182 goto QAllEAsOut;
6183 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006184 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05006185 /* account for prefix user. and trailing null */
6186 rc += (5 + 1 + name_len);
6187 if (rc < (int) buf_size) {
6188 memcpy(EAData, "user.", 5);
6189 EAData += 5;
6190 memcpy(EAData, temp_ptr, name_len);
6191 EAData += name_len;
6192 /* null terminate name */
6193 *EAData = 0;
6194 ++EAData;
6195 } else if (buf_size == 0) {
6196 /* skip copy - calc size only */
6197 } else {
6198 /* stop before overrun buffer */
6199 rc = -ERANGE;
6200 break;
6201 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006202 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05006203 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006204 temp_fea = (struct fea *)temp_ptr;
6205 }
6206
Jeff Layton31c05192010-02-10 16:18:26 -05006207 /* didn't find the named attribute */
6208 if (ea_name)
6209 rc = -ENODATA;
6210
Jeff Laytonf0d38682010-02-10 16:18:26 -05006211QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00006212 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006213 if (rc == -EAGAIN)
6214 goto QAllEAsRetry;
6215
6216 return (ssize_t)rc;
6217}
6218
Linus Torvalds1da177e2005-04-16 15:20:36 -07006219int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006220CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
6221 const char *fileName, const char *ea_name, const void *ea_value,
Steve French50c2f752007-07-13 00:33:32 +00006222 const __u16 ea_value_len, const struct nls_table *nls_codepage,
6223 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006224{
6225 struct smb_com_transaction2_spi_req *pSMB = NULL;
6226 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
6227 struct fealist *parm_data;
6228 int name_len;
6229 int rc = 0;
6230 int bytes_returned = 0;
6231 __u16 params, param_offset, byte_count, offset, count;
6232
Joe Perchesb6b38f72010-04-21 03:50:45 +00006233 cFYI(1, "In SetEA");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006234SetEARetry:
6235 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6236 (void **) &pSMBr);
6237 if (rc)
6238 return rc;
6239
6240 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6241 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006242 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
6243 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006244 name_len++; /* trailing null */
6245 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00006246 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006247 name_len = strnlen(fileName, PATH_MAX);
6248 name_len++; /* trailing null */
6249 strncpy(pSMB->FileName, fileName, name_len);
6250 }
6251
6252 params = 6 + name_len;
6253
6254 /* done calculating parms using name_len of file name,
6255 now use name_len to calculate length of ea name
6256 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00006257 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006258 name_len = 0;
6259 else
Steve French50c2f752007-07-13 00:33:32 +00006260 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006261
Steve Frenchdae5dbd2007-12-30 23:49:57 +00006262 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006263 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006264 /* BB find max SMB PDU from sess */
6265 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006266 pSMB->MaxSetupCount = 0;
6267 pSMB->Reserved = 0;
6268 pSMB->Flags = 0;
6269 pSMB->Timeout = 0;
6270 pSMB->Reserved2 = 0;
6271 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006272 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006273 offset = param_offset + params;
6274 pSMB->InformationLevel =
6275 cpu_to_le16(SMB_SET_FILE_EA);
6276
6277 parm_data =
6278 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
6279 offset);
6280 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6281 pSMB->DataOffset = cpu_to_le16(offset);
6282 pSMB->SetupCount = 1;
6283 pSMB->Reserved3 = 0;
6284 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6285 byte_count = 3 /* pad */ + params + count;
6286 pSMB->DataCount = cpu_to_le16(count);
6287 parm_data->list_len = cpu_to_le32(count);
6288 parm_data->list[0].EA_flags = 0;
6289 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08006290 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006291 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00006292 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00006293 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006294 parm_data->list[0].name[name_len] = 0;
6295 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
6296 /* caller ensures that ea_value_len is less than 64K but
6297 we need to ensure that it fits within the smb */
6298
Steve French50c2f752007-07-13 00:33:32 +00006299 /*BB add length check to see if it would fit in
6300 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00006301 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
6302 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00006303 memcpy(parm_data->list[0].name+name_len+1,
6304 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006305
6306 pSMB->TotalDataCount = pSMB->DataCount;
6307 pSMB->ParameterCount = cpu_to_le16(params);
6308 pSMB->TotalParameterCount = pSMB->ParameterCount;
6309 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006310 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006311 pSMB->ByteCount = cpu_to_le16(byte_count);
6312 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6313 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006314 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00006315 cFYI(1, "SetPathInfo (EA) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006316
6317 cifs_buf_release(pSMB);
6318
6319 if (rc == -EAGAIN)
6320 goto SetEARetry;
6321
6322 return rc;
6323}
Linus Torvalds1da177e2005-04-16 15:20:36 -07006324#endif
Steve French0eff0e22011-02-24 05:39:23 +00006325
6326#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */
6327/*
6328 * Years ago the kernel added a "dnotify" function for Samba server,
6329 * to allow network clients (such as Windows) to display updated
6330 * lists of files in directory listings automatically when
6331 * files are added by one user when another user has the
6332 * same directory open on their desktop. The Linux cifs kernel
6333 * client hooked into the kernel side of this interface for
6334 * the same reason, but ironically when the VFS moved from
6335 * "dnotify" to "inotify" it became harder to plug in Linux
6336 * network file system clients (the most obvious use case
6337 * for notify interfaces is when multiple users can update
6338 * the contents of the same directory - exactly what network
6339 * file systems can do) although the server (Samba) could
6340 * still use it. For the short term we leave the worker
6341 * function ifdeffed out (below) until inotify is fixed
6342 * in the VFS to make it easier to plug in network file
6343 * system clients. If inotify turns out to be permanently
6344 * incompatible for network fs clients, we could instead simply
6345 * expose this config flag by adding a future cifs (and smb2) notify ioctl.
6346 */
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006347int CIFSSMBNotify(const unsigned int xid, struct cifs_tcon *tcon,
Steve French0eff0e22011-02-24 05:39:23 +00006348 const int notify_subdirs, const __u16 netfid,
6349 __u32 filter, struct file *pfile, int multishot,
6350 const struct nls_table *nls_codepage)
6351{
6352 int rc = 0;
6353 struct smb_com_transaction_change_notify_req *pSMB = NULL;
6354 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
6355 struct dir_notify_req *dnotify_req;
6356 int bytes_returned;
6357
6358 cFYI(1, "In CIFSSMBNotify for file handle %d", (int)netfid);
6359 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
6360 (void **) &pSMBr);
6361 if (rc)
6362 return rc;
6363
6364 pSMB->TotalParameterCount = 0 ;
6365 pSMB->TotalDataCount = 0;
6366 pSMB->MaxParameterCount = cpu_to_le32(2);
Jeff Laytonc974bef2011-10-11 06:41:32 -04006367 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Steve French0eff0e22011-02-24 05:39:23 +00006368 pSMB->MaxSetupCount = 4;
6369 pSMB->Reserved = 0;
6370 pSMB->ParameterOffset = 0;
6371 pSMB->DataCount = 0;
6372 pSMB->DataOffset = 0;
6373 pSMB->SetupCount = 4; /* single byte does not need le conversion */
6374 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
6375 pSMB->ParameterCount = pSMB->TotalParameterCount;
6376 if (notify_subdirs)
6377 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
6378 pSMB->Reserved2 = 0;
6379 pSMB->CompletionFilter = cpu_to_le32(filter);
6380 pSMB->Fid = netfid; /* file handle always le */
6381 pSMB->ByteCount = 0;
6382
6383 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6384 (struct smb_hdr *)pSMBr, &bytes_returned,
6385 CIFS_ASYNC_OP);
6386 if (rc) {
6387 cFYI(1, "Error in Notify = %d", rc);
6388 } else {
6389 /* Add file to outstanding requests */
6390 /* BB change to kmem cache alloc */
6391 dnotify_req = kmalloc(
6392 sizeof(struct dir_notify_req),
6393 GFP_KERNEL);
6394 if (dnotify_req) {
6395 dnotify_req->Pid = pSMB->hdr.Pid;
6396 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
6397 dnotify_req->Mid = pSMB->hdr.Mid;
6398 dnotify_req->Tid = pSMB->hdr.Tid;
6399 dnotify_req->Uid = pSMB->hdr.Uid;
6400 dnotify_req->netfid = netfid;
6401 dnotify_req->pfile = pfile;
6402 dnotify_req->filter = filter;
6403 dnotify_req->multishot = multishot;
6404 spin_lock(&GlobalMid_Lock);
6405 list_add_tail(&dnotify_req->lhead,
6406 &GlobalDnotifyReqList);
6407 spin_unlock(&GlobalMid_Lock);
6408 } else
6409 rc = -ENOMEM;
6410 }
6411 cifs_buf_release(pSMB);
6412 return rc;
6413}
6414#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */