blob: 5659850f780a41ac78c83e8f65dd0ef3a8a86fc5 [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
Steve French96daf2b2011-05-27 04:34:02 +0000399CIFSSMBNegotiate(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 Frenchb815f1e52006-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 }
Steve French96daf2b2011-05-27 04:34:02 +0000483 server->sec_mode = (__u8)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 Frenchb815f1e52006-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 Frenchb815f1e52006-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 Frenchb815f1e52006-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 Frenchb815f1e52006-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 Frenchb815f1e52006-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 Frenchb815f1e52006-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 Frenchb815f1e52006-10-02 05:53:29 +0000524 server->timeAdj = result;
Steve French25ee4a92006-09-30 00:54:23 +0000525 } else {
Steve Frenchb815f1e52006-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 Frenchb815f1e52006-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
Steve French96daf2b2011-05-27 04:34:02 +0000697CIFSSMBTDis(const 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 Shilovsky45275782012-05-17 17:53:29 +0400747 add_credits(server, 1);
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 Layton99d86c8f2011-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,
774 server, true);
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
Steve French96daf2b2011-05-27 04:34:02 +0000784CIFSSMBLogoff(const 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
Steve French96daf2b2011-05-27 04:34:02 +0000831CIFSPOSIXDelFile(const int xid, struct cifs_tcon *tcon, const char *fileName,
Steve French2d785a52007-07-15 01:48:57 +0000832 __u16 type, const struct nls_table *nls_codepage, int remap)
833{
834 TRANSACTION2_SPI_REQ *pSMB = NULL;
835 TRANSACTION2_SPI_RSP *pSMBr = NULL;
836 struct unlink_psx_rq *pRqD;
837 int name_len;
838 int rc = 0;
839 int bytes_returned = 0;
840 __u16 params, param_offset, offset, byte_count;
841
Joe Perchesb6b38f72010-04-21 03:50:45 +0000842 cFYI(1, "In POSIX delete");
Steve French2d785a52007-07-15 01:48:57 +0000843PsxDelete:
844 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
845 (void **) &pSMBr);
846 if (rc)
847 return rc;
848
849 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
850 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -0600851 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
852 PATH_MAX, nls_codepage, remap);
Steve French2d785a52007-07-15 01:48:57 +0000853 name_len++; /* trailing null */
854 name_len *= 2;
855 } else { /* BB add path length overrun check */
856 name_len = strnlen(fileName, PATH_MAX);
857 name_len++; /* trailing null */
858 strncpy(pSMB->FileName, fileName, name_len);
859 }
860
861 params = 6 + name_len;
862 pSMB->MaxParameterCount = cpu_to_le16(2);
863 pSMB->MaxDataCount = 0; /* BB double check this with jra */
864 pSMB->MaxSetupCount = 0;
865 pSMB->Reserved = 0;
866 pSMB->Flags = 0;
867 pSMB->Timeout = 0;
868 pSMB->Reserved2 = 0;
869 param_offset = offsetof(struct smb_com_transaction2_spi_req,
870 InformationLevel) - 4;
871 offset = param_offset + params;
872
873 /* Setup pointer to Request Data (inode type) */
874 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
875 pRqD->type = cpu_to_le16(type);
876 pSMB->ParameterOffset = cpu_to_le16(param_offset);
877 pSMB->DataOffset = cpu_to_le16(offset);
878 pSMB->SetupCount = 1;
879 pSMB->Reserved3 = 0;
880 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
881 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
882
883 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
884 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
885 pSMB->ParameterCount = cpu_to_le16(params);
886 pSMB->TotalParameterCount = pSMB->ParameterCount;
887 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
888 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000889 inc_rfc1001_len(pSMB, byte_count);
Steve French2d785a52007-07-15 01:48:57 +0000890 pSMB->ByteCount = cpu_to_le16(byte_count);
891 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
892 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000893 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000894 cFYI(1, "Posix delete returned %d", rc);
Steve French2d785a52007-07-15 01:48:57 +0000895 cifs_buf_release(pSMB);
896
897 cifs_stats_inc(&tcon->num_deletes);
898
899 if (rc == -EAGAIN)
900 goto PsxDelete;
901
902 return rc;
903}
904
905int
Steve French96daf2b2011-05-27 04:34:02 +0000906CIFSSMBDelFile(const int xid, struct cifs_tcon *tcon, const char *fileName,
Steve French737b7582005-04-28 22:41:06 -0700907 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908{
909 DELETE_FILE_REQ *pSMB = NULL;
910 DELETE_FILE_RSP *pSMBr = NULL;
911 int rc = 0;
912 int bytes_returned;
913 int name_len;
914
915DelFileRetry:
916 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
917 (void **) &pSMBr);
918 if (rc)
919 return rc;
920
921 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
922 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -0600923 cifsConvertToUTF16((__le16 *) pSMB->fileName, fileName,
924 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925 name_len++; /* trailing null */
926 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700927 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928 name_len = strnlen(fileName, PATH_MAX);
929 name_len++; /* trailing null */
930 strncpy(pSMB->fileName, fileName, name_len);
931 }
932 pSMB->SearchAttributes =
933 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
934 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000935 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936 pSMB->ByteCount = cpu_to_le16(name_len + 1);
937 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
938 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700939 cifs_stats_inc(&tcon->num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000940 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000941 cFYI(1, "Error in RMFile = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942
943 cifs_buf_release(pSMB);
944 if (rc == -EAGAIN)
945 goto DelFileRetry;
946
947 return rc;
948}
949
950int
Steve French96daf2b2011-05-27 04:34:02 +0000951CIFSSMBRmDir(const int xid, struct cifs_tcon *tcon, const char *dirName,
Steve French737b7582005-04-28 22:41:06 -0700952 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953{
954 DELETE_DIRECTORY_REQ *pSMB = NULL;
955 DELETE_DIRECTORY_RSP *pSMBr = NULL;
956 int rc = 0;
957 int bytes_returned;
958 int name_len;
959
Joe Perchesb6b38f72010-04-21 03:50:45 +0000960 cFYI(1, "In CIFSSMBRmDir");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961RmDirRetry:
962 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
963 (void **) &pSMBr);
964 if (rc)
965 return rc;
966
967 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -0600968 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, dirName,
969 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970 name_len++; /* trailing null */
971 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700972 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973 name_len = strnlen(dirName, PATH_MAX);
974 name_len++; /* trailing null */
975 strncpy(pSMB->DirName, dirName, name_len);
976 }
977
978 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000979 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980 pSMB->ByteCount = cpu_to_le16(name_len + 1);
981 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
982 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700983 cifs_stats_inc(&tcon->num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000984 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000985 cFYI(1, "Error in RMDir = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986
987 cifs_buf_release(pSMB);
988 if (rc == -EAGAIN)
989 goto RmDirRetry;
990 return rc;
991}
992
993int
Steve French96daf2b2011-05-27 04:34:02 +0000994CIFSSMBMkDir(const int xid, struct cifs_tcon *tcon,
Steve French737b7582005-04-28 22:41:06 -0700995 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996{
997 int rc = 0;
998 CREATE_DIRECTORY_REQ *pSMB = NULL;
999 CREATE_DIRECTORY_RSP *pSMBr = NULL;
1000 int bytes_returned;
1001 int name_len;
1002
Joe Perchesb6b38f72010-04-21 03:50:45 +00001003 cFYI(1, "In CIFSSMBMkDir");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004MkDirRetry:
1005 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
1006 (void **) &pSMBr);
1007 if (rc)
1008 return rc;
1009
1010 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06001011 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
1012 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013 name_len++; /* trailing null */
1014 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -07001015 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016 name_len = strnlen(name, PATH_MAX);
1017 name_len++; /* trailing null */
1018 strncpy(pSMB->DirName, name, name_len);
1019 }
1020
1021 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001022 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023 pSMB->ByteCount = cpu_to_le16(name_len + 1);
1024 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1025 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001026 cifs_stats_inc(&tcon->num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +00001027 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001028 cFYI(1, "Error in Mkdir = %d", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07001029
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030 cifs_buf_release(pSMB);
1031 if (rc == -EAGAIN)
1032 goto MkDirRetry;
1033 return rc;
1034}
1035
Steve French2dd29d32007-04-23 22:07:35 +00001036int
Steve French96daf2b2011-05-27 04:34:02 +00001037CIFSPOSIXCreate(const int xid, struct cifs_tcon *tcon, __u32 posix_flags,
Steve Frenchad7a2922008-02-07 23:25:02 +00001038 __u64 mode, __u16 *netfid, FILE_UNIX_BASIC_INFO *pRetData,
Steve French50c2f752007-07-13 00:33:32 +00001039 __u32 *pOplock, const char *name,
Steve French2dd29d32007-04-23 22:07:35 +00001040 const struct nls_table *nls_codepage, int remap)
1041{
1042 TRANSACTION2_SPI_REQ *pSMB = NULL;
1043 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1044 int name_len;
1045 int rc = 0;
1046 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001047 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +00001048 OPEN_PSX_REQ *pdata;
1049 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +00001050
Joe Perchesb6b38f72010-04-21 03:50:45 +00001051 cFYI(1, "In POSIX Create");
Steve French2dd29d32007-04-23 22:07:35 +00001052PsxCreat:
1053 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1054 (void **) &pSMBr);
1055 if (rc)
1056 return rc;
1057
1058 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1059 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001060 cifsConvertToUTF16((__le16 *) pSMB->FileName, name,
1061 PATH_MAX, nls_codepage, remap);
Steve French2dd29d32007-04-23 22:07:35 +00001062 name_len++; /* trailing null */
1063 name_len *= 2;
1064 } else { /* BB improve the check for buffer overruns BB */
1065 name_len = strnlen(name, PATH_MAX);
1066 name_len++; /* trailing null */
1067 strncpy(pSMB->FileName, name, name_len);
1068 }
1069
1070 params = 6 + name_len;
1071 count = sizeof(OPEN_PSX_REQ);
1072 pSMB->MaxParameterCount = cpu_to_le16(2);
1073 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1074 pSMB->MaxSetupCount = 0;
1075 pSMB->Reserved = 0;
1076 pSMB->Flags = 0;
1077 pSMB->Timeout = 0;
1078 pSMB->Reserved2 = 0;
1079 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001080 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001081 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001082 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001083 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001084 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001085 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001086 pdata->OpenFlags = cpu_to_le32(*pOplock);
1087 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1088 pSMB->DataOffset = cpu_to_le16(offset);
1089 pSMB->SetupCount = 1;
1090 pSMB->Reserved3 = 0;
1091 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1092 byte_count = 3 /* pad */ + params + count;
1093
1094 pSMB->DataCount = cpu_to_le16(count);
1095 pSMB->ParameterCount = cpu_to_le16(params);
1096 pSMB->TotalDataCount = pSMB->DataCount;
1097 pSMB->TotalParameterCount = pSMB->ParameterCount;
1098 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1099 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001100 inc_rfc1001_len(pSMB, byte_count);
Steve French2dd29d32007-04-23 22:07:35 +00001101 pSMB->ByteCount = cpu_to_le16(byte_count);
1102 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1103 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1104 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001105 cFYI(1, "Posix create returned %d", rc);
Steve French2dd29d32007-04-23 22:07:35 +00001106 goto psx_create_err;
1107 }
1108
Joe Perchesb6b38f72010-04-21 03:50:45 +00001109 cFYI(1, "copying inode info");
Steve French2dd29d32007-04-23 22:07:35 +00001110 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1111
Jeff Layton820a8032011-05-04 08:05:26 -04001112 if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) {
Steve French2dd29d32007-04-23 22:07:35 +00001113 rc = -EIO; /* bad smb */
1114 goto psx_create_err;
1115 }
1116
1117 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001118 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001119 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001120
Steve French2dd29d32007-04-23 22:07:35 +00001121 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001122 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001123 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1124 /* Let caller know file was created so we can set the mode. */
1125 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001126 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001127 *pOplock |= CIFS_CREATE_ACTION;
1128 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001129 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1130 pRetData->Type = cpu_to_le32(-1); /* unknown */
Joe Perchesb6b38f72010-04-21 03:50:45 +00001131 cFYI(DBG2, "unknown type");
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001132 } else {
Jeff Layton820a8032011-05-04 08:05:26 -04001133 if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001134 + sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001135 cERROR(1, "Open response data too small");
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001136 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001137 goto psx_create_err;
1138 }
Steve French50c2f752007-07-13 00:33:32 +00001139 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001140 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001141 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001142 }
Steve French2dd29d32007-04-23 22:07:35 +00001143
1144psx_create_err:
1145 cifs_buf_release(pSMB);
1146
Steve French65bc98b2009-07-10 15:27:25 +00001147 if (posix_flags & SMB_O_DIRECTORY)
1148 cifs_stats_inc(&tcon->num_posixmkdirs);
1149 else
1150 cifs_stats_inc(&tcon->num_posixopens);
Steve French2dd29d32007-04-23 22:07:35 +00001151
1152 if (rc == -EAGAIN)
1153 goto PsxCreat;
1154
Steve French50c2f752007-07-13 00:33:32 +00001155 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001156}
1157
Steve Frencha9d02ad2005-08-24 23:06:05 -07001158static __u16 convert_disposition(int disposition)
1159{
1160 __u16 ofun = 0;
1161
1162 switch (disposition) {
1163 case FILE_SUPERSEDE:
1164 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1165 break;
1166 case FILE_OPEN:
1167 ofun = SMBOPEN_OAPPEND;
1168 break;
1169 case FILE_CREATE:
1170 ofun = SMBOPEN_OCREATE;
1171 break;
1172 case FILE_OPEN_IF:
1173 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1174 break;
1175 case FILE_OVERWRITE:
1176 ofun = SMBOPEN_OTRUNC;
1177 break;
1178 case FILE_OVERWRITE_IF:
1179 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1180 break;
1181 default:
Joe Perchesb6b38f72010-04-21 03:50:45 +00001182 cFYI(1, "unknown disposition %d", disposition);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001183 ofun = SMBOPEN_OAPPEND; /* regular open */
1184 }
1185 return ofun;
1186}
1187
Jeff Layton35fc37d2008-05-14 10:22:03 -07001188static int
1189access_flags_to_smbopen_mode(const int access_flags)
1190{
1191 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1192
1193 if (masked_flags == GENERIC_READ)
1194 return SMBOPEN_READ;
1195 else if (masked_flags == GENERIC_WRITE)
1196 return SMBOPEN_WRITE;
1197
1198 /* just go for read/write */
1199 return SMBOPEN_READWRITE;
1200}
1201
Steve Frencha9d02ad2005-08-24 23:06:05 -07001202int
Steve French96daf2b2011-05-27 04:34:02 +00001203SMBLegacyOpen(const int xid, struct cifs_tcon *tcon,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001204 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001205 const int access_flags, const int create_options, __u16 *netfid,
1206 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001207 const struct nls_table *nls_codepage, int remap)
1208{
1209 int rc = -EACCES;
1210 OPENX_REQ *pSMB = NULL;
1211 OPENX_RSP *pSMBr = NULL;
1212 int bytes_returned;
1213 int name_len;
1214 __u16 count;
1215
1216OldOpenRetry:
1217 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1218 (void **) &pSMBr);
1219 if (rc)
1220 return rc;
1221
1222 pSMB->AndXCommand = 0xFF; /* none */
1223
1224 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1225 count = 1; /* account for one byte pad to word boundary */
1226 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001227 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1228 fileName, PATH_MAX, nls_codepage, remap);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001229 name_len++; /* trailing null */
1230 name_len *= 2;
1231 } else { /* BB improve check for buffer overruns BB */
1232 count = 0; /* no pad */
1233 name_len = strnlen(fileName, PATH_MAX);
1234 name_len++; /* trailing null */
1235 strncpy(pSMB->fileName, fileName, name_len);
1236 }
1237 if (*pOplock & REQ_OPLOCK)
1238 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001239 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001240 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001241
Steve Frencha9d02ad2005-08-24 23:06:05 -07001242 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001243 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001244 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1245 /* set file as system file if special file such
1246 as fifo and server expecting SFU style and
1247 no Unix extensions */
1248
Steve French790fe572007-07-07 19:25:05 +00001249 if (create_options & CREATE_OPTION_SPECIAL)
1250 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001251 else /* BB FIXME BB */
1252 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001253
Jeff Layton67750fb2008-05-09 22:28:02 +00001254 if (create_options & CREATE_OPTION_READONLY)
1255 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001256
1257 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001258/* pSMB->CreateOptions = cpu_to_le32(create_options &
1259 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001260 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001261
1262 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001263 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001264 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001265 inc_rfc1001_len(pSMB, count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001266
1267 pSMB->ByteCount = cpu_to_le16(count);
1268 /* long_op set to 1 to allow for oplock break timeouts */
1269 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001270 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001271 cifs_stats_inc(&tcon->num_opens);
1272 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001273 cFYI(1, "Error in Open = %d", rc);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001274 } else {
1275 /* BB verify if wct == 15 */
1276
Steve French582d21e2008-05-13 04:54:12 +00001277/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001278
1279 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1280 /* Let caller know file was created so we can set the mode. */
1281 /* Do we care about the CreateAction in any other cases? */
1282 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001283/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001284 *pOplock |= CIFS_CREATE_ACTION; */
1285 /* BB FIXME END */
1286
Steve French790fe572007-07-07 19:25:05 +00001287 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001288 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1289 pfile_info->LastAccessTime = 0; /* BB fixme */
1290 pfile_info->LastWriteTime = 0; /* BB fixme */
1291 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001292 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001293 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001294 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001295 pfile_info->AllocationSize =
1296 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1297 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001298 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001299 pfile_info->DeletePending = 0;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001300 }
1301 }
1302
1303 cifs_buf_release(pSMB);
1304 if (rc == -EAGAIN)
1305 goto OldOpenRetry;
1306 return rc;
1307}
1308
Linus Torvalds1da177e2005-04-16 15:20:36 -07001309int
Steve French96daf2b2011-05-27 04:34:02 +00001310CIFSSMBOpen(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001312 const int access_flags, const int create_options, __u16 *netfid,
1313 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001314 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315{
1316 int rc = -EACCES;
1317 OPEN_REQ *pSMB = NULL;
1318 OPEN_RSP *pSMBr = NULL;
1319 int bytes_returned;
1320 int name_len;
1321 __u16 count;
1322
1323openRetry:
1324 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1325 (void **) &pSMBr);
1326 if (rc)
1327 return rc;
1328
1329 pSMB->AndXCommand = 0xFF; /* none */
1330
1331 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1332 count = 1; /* account for one byte pad to word boundary */
1333 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001334 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1335 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336 name_len++; /* trailing null */
1337 name_len *= 2;
1338 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001339 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340 count = 0; /* no pad */
1341 name_len = strnlen(fileName, PATH_MAX);
1342 name_len++; /* trailing null */
1343 pSMB->NameLength = cpu_to_le16(name_len);
1344 strncpy(pSMB->fileName, fileName, name_len);
1345 }
1346 if (*pOplock & REQ_OPLOCK)
1347 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001348 else if (*pOplock & REQ_BATCHOPLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1351 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -07001352 /* set file as system file if special file such
1353 as fifo and server expecting SFU style and
1354 no Unix extensions */
Steve French790fe572007-07-07 19:25:05 +00001355 if (create_options & CREATE_OPTION_SPECIAL)
Steve Frencheda3c0292005-07-21 15:20:28 -07001356 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1357 else
1358 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Jeff Layton67750fb2008-05-09 22:28:02 +00001359
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360 /* XP does not handle ATTR_POSIX_SEMANTICS */
1361 /* but it helps speed up case sensitive checks for other
1362 servers such as Samba */
1363 if (tcon->ses->capabilities & CAP_UNIX)
1364 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1365
Jeff Layton67750fb2008-05-09 22:28:02 +00001366 if (create_options & CREATE_OPTION_READONLY)
1367 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1368
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1370 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -07001371 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001372 /* BB Expirement with various impersonation levels and verify */
1373 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374 pSMB->SecurityFlags =
1375 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1376
1377 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001378 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379
1380 pSMB->ByteCount = cpu_to_le16(count);
1381 /* long_op set to 1 to allow for oplock break timeouts */
1382 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001383 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001384 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001386 cFYI(1, "Error in Open = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387 } else {
Steve French09d1db52005-04-28 22:41:08 -07001388 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1390 /* Let caller know file was created so we can set the mode. */
1391 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001392 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve French50c2f752007-07-13 00:33:32 +00001393 *pOplock |= CIFS_CREATE_ACTION;
Steve French790fe572007-07-07 19:25:05 +00001394 if (pfile_info) {
Steve French61e74802008-12-03 00:57:54 +00001395 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1396 36 /* CreationTime to Attributes */);
1397 /* the file_info buf is endian converted by caller */
1398 pfile_info->AllocationSize = pSMBr->AllocationSize;
1399 pfile_info->EndOfFile = pSMBr->EndOfFile;
1400 pfile_info->NumberOfLinks = cpu_to_le32(1);
1401 pfile_info->DeletePending = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001404
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405 cifs_buf_release(pSMB);
1406 if (rc == -EAGAIN)
1407 goto openRetry;
1408 return rc;
1409}
1410
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001411/*
1412 * Discard any remaining data in the current SMB. To do this, we borrow the
1413 * current bigbuf.
1414 */
1415static int
1416cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1417{
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001418 unsigned int rfclen = get_rfc1002_length(server->smallbuf);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001419 int remaining = rfclen + 4 - server->total_read;
1420 struct cifs_readdata *rdata = mid->callback_data;
1421
1422 while (remaining > 0) {
1423 int length;
1424
1425 length = cifs_read_from_socket(server, server->bigbuf,
1426 min_t(unsigned int, remaining,
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001427 CIFSMaxBufSize + MAX_HEADER_SIZE(server)));
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001428 if (length < 0)
1429 return length;
1430 server->total_read += length;
1431 remaining -= length;
1432 }
1433
1434 dequeue_mid(mid, rdata->result);
1435 return 0;
1436}
1437
1438static int
1439cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1440{
1441 int length, len;
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001442 unsigned int data_offset, data_len;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001443 struct cifs_readdata *rdata = mid->callback_data;
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001444 char *buf = server->smallbuf;
1445 unsigned int buflen = get_rfc1002_length(buf) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001446
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001447 cFYI(1, "%s: mid=%llu offset=%llu bytes=%u", __func__,
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001448 mid->mid, rdata->offset, rdata->bytes);
1449
1450 /*
1451 * read the rest of READ_RSP header (sans Data array), or whatever we
1452 * can if there's not enough data. At this point, we've read down to
1453 * the Mid.
1454 */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001455 len = min_t(unsigned int, buflen, server->vals->read_rsp_size) -
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001456 HEADER_SIZE(server) + 1;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001457
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001458 rdata->iov[0].iov_base = buf + HEADER_SIZE(server) - 1;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001459 rdata->iov[0].iov_len = len;
1460
1461 length = cifs_readv_from_socket(server, rdata->iov, 1, len);
1462 if (length < 0)
1463 return length;
1464 server->total_read += length;
1465
1466 /* Was the SMB read successful? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001467 rdata->result = server->ops->map_error(buf, false);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001468 if (rdata->result != 0) {
1469 cFYI(1, "%s: server returned error %d", __func__,
1470 rdata->result);
1471 return cifs_readv_discard(server, mid);
1472 }
1473
1474 /* Is there enough to get to the rest of the READ_RSP header? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001475 if (server->total_read < server->vals->read_rsp_size) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001476 cFYI(1, "%s: server returned short header. got=%u expected=%zu",
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001477 __func__, server->total_read,
1478 server->vals->read_rsp_size);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001479 rdata->result = -EIO;
1480 return cifs_readv_discard(server, mid);
1481 }
1482
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001483 data_offset = server->ops->read_data_offset(buf) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001484 if (data_offset < server->total_read) {
1485 /*
1486 * win2k8 sometimes sends an offset of 0 when the read
1487 * is beyond the EOF. Treat it as if the data starts just after
1488 * the header.
1489 */
1490 cFYI(1, "%s: data offset (%u) inside read response header",
1491 __func__, data_offset);
1492 data_offset = server->total_read;
1493 } else if (data_offset > MAX_CIFS_SMALL_BUFFER_SIZE) {
1494 /* data_offset is beyond the end of smallbuf */
1495 cFYI(1, "%s: data offset (%u) beyond end of smallbuf",
1496 __func__, data_offset);
1497 rdata->result = -EIO;
1498 return cifs_readv_discard(server, mid);
1499 }
1500
1501 cFYI(1, "%s: total_read=%u data_offset=%u", __func__,
1502 server->total_read, data_offset);
1503
1504 len = data_offset - server->total_read;
1505 if (len > 0) {
1506 /* read any junk before data into the rest of smallbuf */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001507 rdata->iov[0].iov_base = buf + server->total_read;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001508 rdata->iov[0].iov_len = len;
1509 length = cifs_readv_from_socket(server, rdata->iov, 1, len);
1510 if (length < 0)
1511 return length;
1512 server->total_read += length;
1513 }
1514
1515 /* set up first iov for signature check */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001516 rdata->iov[0].iov_base = buf;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001517 rdata->iov[0].iov_len = server->total_read;
1518 cFYI(1, "0: iov_base=%p iov_len=%zu",
1519 rdata->iov[0].iov_base, rdata->iov[0].iov_len);
1520
1521 /* how much data is in the response? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001522 data_len = server->ops->read_data_length(buf);
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001523 if (data_offset + data_len > buflen) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001524 /* data_len is corrupt -- discard frame */
1525 rdata->result = -EIO;
1526 return cifs_readv_discard(server, mid);
1527 }
1528
1529 /* marshal up the page array */
Jeff Layton3cf003c2012-07-11 09:09:36 -04001530 cifs_kmap_lock();
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001531 len = rdata->marshal_iov(rdata, data_len);
Jeff Layton3cf003c2012-07-11 09:09:36 -04001532 cifs_kmap_unlock();
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001533 data_len -= len;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001534
1535 /* issue the read if we have any iovecs left to fill */
1536 if (rdata->nr_iov > 1) {
1537 length = cifs_readv_from_socket(server, &rdata->iov[1],
1538 rdata->nr_iov - 1, len);
1539 if (length < 0)
1540 return length;
1541 server->total_read += length;
1542 } else {
1543 length = 0;
1544 }
1545
1546 rdata->bytes = length;
1547
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001548 cFYI(1, "total_read=%u buflen=%u remaining=%u", server->total_read,
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001549 buflen, data_len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001550
1551 /* discard anything left over */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001552 if (server->total_read < buflen)
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001553 return cifs_readv_discard(server, mid);
1554
1555 dequeue_mid(mid, false);
1556 return length;
1557}
1558
1559static void
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001560cifs_readv_callback(struct mid_q_entry *mid)
1561{
1562 struct cifs_readdata *rdata = mid->callback_data;
1563 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1564 struct TCP_Server_Info *server = tcon->ses->server;
1565
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001566 cFYI(1, "%s: mid=%llu state=%d result=%d bytes=%u", __func__,
1567 mid->mid, mid->mid_state, rdata->result, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001568
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001569 switch (mid->mid_state) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001570 case MID_RESPONSE_RECEIVED:
1571 /* result already set, check signature */
1572 if (server->sec_mode &
1573 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
1574 if (cifs_verify_signature(rdata->iov, rdata->nr_iov,
1575 server, mid->sequence_number + 1))
1576 cERROR(1, "Unexpected SMB signature");
1577 }
1578 /* FIXME: should this be counted toward the initiating task? */
1579 task_io_account_read(rdata->bytes);
1580 cifs_stats_bytes_read(tcon, rdata->bytes);
1581 break;
1582 case MID_REQUEST_SUBMITTED:
1583 case MID_RETRY_NEEDED:
1584 rdata->result = -EAGAIN;
1585 break;
1586 default:
1587 rdata->result = -EIO;
1588 }
1589
Jeff Laytonda472fc2012-03-23 14:40:53 -04001590 queue_work(cifsiod_wq, &rdata->work);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001591 DeleteMidQEntry(mid);
Pavel Shilovsky45275782012-05-17 17:53:29 +04001592 add_credits(server, 1);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001593}
1594
1595/* cifs_async_readv - send an async write, and set up mid to handle result */
1596int
1597cifs_async_readv(struct cifs_readdata *rdata)
1598{
1599 int rc;
1600 READ_REQ *smb = NULL;
1601 int wct;
1602 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1603
1604 cFYI(1, "%s: offset=%llu bytes=%u", __func__,
1605 rdata->offset, rdata->bytes);
1606
1607 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1608 wct = 12;
1609 else {
1610 wct = 10; /* old style read */
1611 if ((rdata->offset >> 32) > 0) {
1612 /* can not handle this big offset for old */
1613 return -EIO;
1614 }
1615 }
1616
1617 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **)&smb);
1618 if (rc)
1619 return rc;
1620
1621 smb->hdr.Pid = cpu_to_le16((__u16)rdata->pid);
1622 smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16));
1623
1624 smb->AndXCommand = 0xFF; /* none */
1625 smb->Fid = rdata->cfile->netfid;
1626 smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF);
1627 if (wct == 12)
1628 smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32);
1629 smb->Remaining = 0;
1630 smb->MaxCount = cpu_to_le16(rdata->bytes & 0xFFFF);
1631 smb->MaxCountHigh = cpu_to_le32(rdata->bytes >> 16);
1632 if (wct == 12)
1633 smb->ByteCount = 0;
1634 else {
1635 /* old style read */
1636 struct smb_com_readx_req *smbr =
1637 (struct smb_com_readx_req *)smb;
1638 smbr->ByteCount = 0;
1639 }
1640
1641 /* 4 for RFC1001 length + 1 for BCC */
1642 rdata->iov[0].iov_base = smb;
1643 rdata->iov[0].iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
1644
Jeff Layton6993f742012-05-16 07:13:17 -04001645 kref_get(&rdata->refcount);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001646 rc = cifs_call_async(tcon->ses->server, rdata->iov, 1,
1647 cifs_readv_receive, cifs_readv_callback,
1648 rdata, false);
1649
1650 if (rc == 0)
1651 cifs_stats_inc(&tcon->num_reads);
Jeff Layton6993f742012-05-16 07:13:17 -04001652 else
1653 kref_put(&rdata->refcount, cifs_readdata_release);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001654
1655 cifs_small_buf_release(smb);
1656 return rc;
1657}
1658
Linus Torvalds1da177e2005-04-16 15:20:36 -07001659int
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001660CIFSSMBRead(const int xid, struct cifs_io_parms *io_parms, unsigned int *nbytes,
Steve French50c2f752007-07-13 00:33:32 +00001661 char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662{
1663 int rc = -EACCES;
1664 READ_REQ *pSMB = NULL;
1665 READ_RSP *pSMBr = NULL;
1666 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001667 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001668 int resp_buf_type = 0;
1669 struct kvec iov[1];
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001670 __u32 pid = io_parms->pid;
1671 __u16 netfid = io_parms->netfid;
1672 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001673 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001674 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675
Joe Perchesb6b38f72010-04-21 03:50:45 +00001676 cFYI(1, "Reading %d bytes on fid %d", count, netfid);
Steve French790fe572007-07-07 19:25:05 +00001677 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001678 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001679 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001680 wct = 10; /* old style read */
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001681 if ((offset >> 32) > 0) {
Steve French4c3130e2008-12-09 00:28:16 +00001682 /* can not handle this big offset for old */
1683 return -EIO;
1684 }
1685 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686
1687 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001688 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689 if (rc)
1690 return rc;
1691
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001692 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1693 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1694
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695 /* tcon and ses pointer are checked in smb_init */
1696 if (tcon->ses->server == NULL)
1697 return -ECONNABORTED;
1698
Steve Frenchec637e32005-12-12 20:53:18 -08001699 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700 pSMB->Fid = netfid;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001701 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001702 if (wct == 12)
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001703 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001704
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705 pSMB->Remaining = 0;
1706 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1707 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001708 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001709 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1710 else {
1711 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001712 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001713 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001714 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001715 }
Steve Frenchec637e32005-12-12 20:53:18 -08001716
1717 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001718 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve Frencha761ac52007-10-18 21:45:27 +00001719 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Jeff Layton77499812011-01-11 07:24:23 -05001720 &resp_buf_type, CIFS_LOG_ERROR);
Steve Frencha4544342005-08-24 13:59:35 -07001721 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001722 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001724 cERROR(1, "Send error in read = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725 } else {
1726 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1727 data_length = data_length << 16;
1728 data_length += le16_to_cpu(pSMBr->DataLength);
1729 *nbytes = data_length;
1730
1731 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001732 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733 || (data_length > count)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001734 cFYI(1, "bad length %d for count %d",
1735 data_length, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736 rc = -EIO;
1737 *nbytes = 0;
1738 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001739 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001740 le16_to_cpu(pSMBr->DataOffset);
1741/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001742 cERROR(1, "Faulting on read rc = %d",rc);
Steve French50c2f752007-07-13 00:33:32 +00001743 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001744 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001745 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001746 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001747 }
1748 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749
Steve French4b8f9302006-02-26 16:41:18 +00001750/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001751 if (*buf) {
1752 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001753 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001754 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001755 cifs_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001756 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001757 /* return buffer to caller to free */
1758 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001759 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001760 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001761 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001762 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001763 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001764
1765 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766 since file handle passed in no longer valid */
1767 return rc;
1768}
1769
Steve Frenchec637e32005-12-12 20:53:18 -08001770
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771int
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001772CIFSSMBWrite(const int xid, struct cifs_io_parms *io_parms,
1773 unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001774 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001775{
1776 int rc = -EACCES;
1777 WRITE_REQ *pSMB = NULL;
1778 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001779 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780 __u32 bytes_sent;
1781 __u16 byte_count;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001782 __u32 pid = io_parms->pid;
1783 __u16 netfid = io_parms->netfid;
1784 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001785 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001786 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787
Steve Frencha24e2d72010-04-03 17:20:21 +00001788 *nbytes = 0;
1789
Joe Perchesb6b38f72010-04-21 03:50:45 +00001790 /* cFYI(1, "write at %lld %d bytes", offset, count);*/
Steve French790fe572007-07-07 19:25:05 +00001791 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001792 return -ECONNABORTED;
1793
Steve French790fe572007-07-07 19:25:05 +00001794 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001795 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001796 else {
Steve French1c955182005-08-30 20:58:07 -07001797 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001798 if ((offset >> 32) > 0) {
1799 /* can not handle big offset for old srv */
1800 return -EIO;
1801 }
1802 }
Steve French1c955182005-08-30 20:58:07 -07001803
1804 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805 (void **) &pSMBr);
1806 if (rc)
1807 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001808
1809 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1810 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1811
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812 /* tcon and ses pointer are checked in smb_init */
1813 if (tcon->ses->server == NULL)
1814 return -ECONNABORTED;
1815
1816 pSMB->AndXCommand = 0xFF; /* none */
1817 pSMB->Fid = netfid;
1818 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001819 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001820 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001821
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822 pSMB->Reserved = 0xFFFFFFFF;
1823 pSMB->WriteMode = 0;
1824 pSMB->Remaining = 0;
1825
Steve French50c2f752007-07-13 00:33:32 +00001826 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001827 can send more if LARGE_WRITE_X capability returned by the server and if
1828 our buffer is big enough or if we convert to iovecs on socket writes
1829 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001830 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001831 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1832 } else {
1833 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1834 & ~0xFF;
1835 }
1836
1837 if (bytes_sent > count)
1838 bytes_sent = count;
1839 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001840 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001841 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001842 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001843 else if (ubuf) {
1844 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845 cifs_buf_release(pSMB);
1846 return -EFAULT;
1847 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001848 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849 /* No buffer */
1850 cifs_buf_release(pSMB);
1851 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001852 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001853 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001854 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001855 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001856 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001857
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1859 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001860 inc_rfc1001_len(pSMB, byte_count);
Steve French1c955182005-08-30 20:58:07 -07001861
Steve French790fe572007-07-07 19:25:05 +00001862 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001863 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001864 else { /* old style write has byte count 4 bytes earlier
1865 so 4 bytes pad */
1866 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001867 (struct smb_com_writex_req *)pSMB;
1868 pSMBW->ByteCount = cpu_to_le16(byte_count);
1869 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870
1871 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1872 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001873 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00001875 cFYI(1, "Send error in write = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876 } else {
1877 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1878 *nbytes = (*nbytes) << 16;
1879 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301880
1881 /*
1882 * Mask off high 16 bits when bytes written as returned by the
1883 * server is greater than bytes requested by the client. Some
1884 * OS/2 servers are known to set incorrect CountHigh values.
1885 */
1886 if (*nbytes > count)
1887 *nbytes &= 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888 }
1889
1890 cifs_buf_release(pSMB);
1891
Steve French50c2f752007-07-13 00:33:32 +00001892 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893 since file handle passed in no longer valid */
1894
1895 return rc;
1896}
1897
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001898void
1899cifs_writedata_release(struct kref *refcount)
1900{
1901 struct cifs_writedata *wdata = container_of(refcount,
1902 struct cifs_writedata, refcount);
1903
1904 if (wdata->cfile)
1905 cifsFileInfo_put(wdata->cfile);
1906
1907 kfree(wdata);
1908}
1909
1910/*
1911 * Write failed with a retryable error. Resend the write request. It's also
1912 * possible that the page was redirtied so re-clean the page.
1913 */
1914static void
1915cifs_writev_requeue(struct cifs_writedata *wdata)
1916{
1917 int i, rc;
1918 struct inode *inode = wdata->cfile->dentry->d_inode;
1919
1920 for (i = 0; i < wdata->nr_pages; i++) {
1921 lock_page(wdata->pages[i]);
1922 clear_page_dirty_for_io(wdata->pages[i]);
1923 }
1924
1925 do {
1926 rc = cifs_async_writev(wdata);
1927 } while (rc == -EAGAIN);
1928
1929 for (i = 0; i < wdata->nr_pages; i++) {
1930 if (rc != 0)
1931 SetPageError(wdata->pages[i]);
1932 unlock_page(wdata->pages[i]);
1933 }
1934
1935 mapping_set_error(inode->i_mapping, rc);
1936 kref_put(&wdata->refcount, cifs_writedata_release);
1937}
1938
Jeff Laytonc2e87642012-03-23 14:40:55 -04001939void
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001940cifs_writev_complete(struct work_struct *work)
1941{
1942 struct cifs_writedata *wdata = container_of(work,
1943 struct cifs_writedata, work);
1944 struct inode *inode = wdata->cfile->dentry->d_inode;
1945 int i = 0;
1946
1947 if (wdata->result == 0) {
Jeff Layton597b0272012-03-23 14:40:56 -04001948 spin_lock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001949 cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
Jeff Layton597b0272012-03-23 14:40:56 -04001950 spin_unlock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001951 cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
1952 wdata->bytes);
1953 } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
1954 return cifs_writev_requeue(wdata);
1955
1956 for (i = 0; i < wdata->nr_pages; i++) {
1957 struct page *page = wdata->pages[i];
1958 if (wdata->result == -EAGAIN)
1959 __set_page_dirty_nobuffers(page);
1960 else if (wdata->result < 0)
1961 SetPageError(page);
1962 end_page_writeback(page);
1963 page_cache_release(page);
1964 }
1965 if (wdata->result != -EAGAIN)
1966 mapping_set_error(inode->i_mapping, wdata->result);
1967 kref_put(&wdata->refcount, cifs_writedata_release);
1968}
1969
1970struct cifs_writedata *
Jeff Laytonc2e87642012-03-23 14:40:55 -04001971cifs_writedata_alloc(unsigned int nr_pages, work_func_t complete)
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001972{
1973 struct cifs_writedata *wdata;
1974
1975 /* this would overflow */
1976 if (nr_pages == 0) {
1977 cERROR(1, "%s: called with nr_pages == 0!", __func__);
1978 return NULL;
1979 }
1980
1981 /* writedata + number of page pointers */
1982 wdata = kzalloc(sizeof(*wdata) +
1983 sizeof(struct page *) * (nr_pages - 1), GFP_NOFS);
1984 if (wdata != NULL) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001985 kref_init(&wdata->refcount);
Jeff Laytonda82f7e2012-03-23 14:40:56 -04001986 INIT_LIST_HEAD(&wdata->list);
1987 init_completion(&wdata->done);
1988 INIT_WORK(&wdata->work, complete);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001989 }
1990 return wdata;
1991}
1992
1993/*
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001994 * Check the mid_state and signature on received buffer (if any), and queue the
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001995 * workqueue completion task.
1996 */
1997static void
1998cifs_writev_callback(struct mid_q_entry *mid)
1999{
2000 struct cifs_writedata *wdata = mid->callback_data;
Steve French96daf2b2011-05-27 04:34:02 +00002001 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002002 unsigned int written;
2003 WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
2004
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04002005 switch (mid->mid_state) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002006 case MID_RESPONSE_RECEIVED:
2007 wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
2008 if (wdata->result != 0)
2009 break;
2010
2011 written = le16_to_cpu(smb->CountHigh);
2012 written <<= 16;
2013 written += le16_to_cpu(smb->Count);
2014 /*
2015 * Mask off high 16 bits when bytes written as returned
2016 * by the server is greater than bytes requested by the
2017 * client. OS/2 servers are known to set incorrect
2018 * CountHigh values.
2019 */
2020 if (written > wdata->bytes)
2021 written &= 0xFFFF;
2022
2023 if (written < wdata->bytes)
2024 wdata->result = -ENOSPC;
2025 else
2026 wdata->bytes = written;
2027 break;
2028 case MID_REQUEST_SUBMITTED:
2029 case MID_RETRY_NEEDED:
2030 wdata->result = -EAGAIN;
2031 break;
2032 default:
2033 wdata->result = -EIO;
2034 break;
2035 }
2036
Jeff Laytonda472fc2012-03-23 14:40:53 -04002037 queue_work(cifsiod_wq, &wdata->work);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002038 DeleteMidQEntry(mid);
Pavel Shilovsky45275782012-05-17 17:53:29 +04002039 add_credits(tcon->ses->server, 1);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002040}
2041
2042/* cifs_async_writev - send an async write, and set up mid to handle result */
2043int
2044cifs_async_writev(struct cifs_writedata *wdata)
2045{
2046 int i, rc = -EACCES;
2047 WRITE_REQ *smb = NULL;
2048 int wct;
Steve French96daf2b2011-05-27 04:34:02 +00002049 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002050 struct kvec *iov = NULL;
2051
2052 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
2053 wct = 14;
2054 } else {
2055 wct = 12;
2056 if (wdata->offset >> 32 > 0) {
2057 /* can not handle big offset for old srv */
2058 return -EIO;
2059 }
2060 }
2061
2062 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
2063 if (rc)
2064 goto async_writev_out;
2065
2066 /* 1 iov per page + 1 for header */
2067 iov = kzalloc((wdata->nr_pages + 1) * sizeof(*iov), GFP_NOFS);
2068 if (iov == NULL) {
2069 rc = -ENOMEM;
2070 goto async_writev_out;
2071 }
2072
Jeff Laytonfe5f5d22012-03-23 14:40:55 -04002073 smb->hdr.Pid = cpu_to_le16((__u16)wdata->pid);
2074 smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16));
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002075
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002076 smb->AndXCommand = 0xFF; /* none */
2077 smb->Fid = wdata->cfile->netfid;
2078 smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
2079 if (wct == 14)
2080 smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
2081 smb->Reserved = 0xFFFFFFFF;
2082 smb->WriteMode = 0;
2083 smb->Remaining = 0;
2084
2085 smb->DataOffset =
2086 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
2087
2088 /* 4 for RFC1001 length + 1 for BCC */
2089 iov[0].iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4 + 1;
2090 iov[0].iov_base = smb;
2091
Jeff Laytone9492872012-03-23 14:40:56 -04002092 /*
2093 * This function should marshal up the page array into the kvec
2094 * array, reserving [0] for the header. It should kmap the pages
2095 * and set the iov_len properly for each one. It may also set
2096 * wdata->bytes too.
2097 */
Jeff Layton3cf003c2012-07-11 09:09:36 -04002098 cifs_kmap_lock();
Jeff Laytone9492872012-03-23 14:40:56 -04002099 wdata->marshal_iov(iov, wdata);
Jeff Layton3cf003c2012-07-11 09:09:36 -04002100 cifs_kmap_unlock();
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002101
2102 cFYI(1, "async write at %llu %u bytes", wdata->offset, wdata->bytes);
2103
2104 smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
2105 smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16);
2106
2107 if (wct == 14) {
2108 inc_rfc1001_len(&smb->hdr, wdata->bytes + 1);
2109 put_bcc(wdata->bytes + 1, &smb->hdr);
2110 } else {
2111 /* wct == 12 */
2112 struct smb_com_writex_req *smbw =
2113 (struct smb_com_writex_req *)smb;
2114 inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
2115 put_bcc(wdata->bytes + 5, &smbw->hdr);
2116 iov[0].iov_len += 4; /* pad bigger by four bytes */
2117 }
2118
2119 kref_get(&wdata->refcount);
2120 rc = cifs_call_async(tcon->ses->server, iov, wdata->nr_pages + 1,
Jeff Layton44d22d82011-10-19 15:29:49 -04002121 NULL, cifs_writev_callback, wdata, false);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002122
2123 if (rc == 0)
2124 cifs_stats_inc(&tcon->num_writes);
2125 else
2126 kref_put(&wdata->refcount, cifs_writedata_release);
2127
2128 /* send is done, unmap pages */
2129 for (i = 0; i < wdata->nr_pages; i++)
2130 kunmap(wdata->pages[i]);
2131
2132async_writev_out:
2133 cifs_small_buf_release(smb);
2134 kfree(iov);
2135 return rc;
2136}
2137
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002138int
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002139CIFSSMBWrite2(const int xid, struct cifs_io_parms *io_parms,
2140 unsigned int *nbytes, struct kvec *iov, int n_vec,
2141 const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002142{
2143 int rc = -EACCES;
2144 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08002145 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002146 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08002147 int resp_buf_type = 0;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002148 __u32 pid = io_parms->pid;
2149 __u16 netfid = io_parms->netfid;
2150 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00002151 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002152 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002153
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04002154 *nbytes = 0;
2155
Joe Perchesb6b38f72010-04-21 03:50:45 +00002156 cFYI(1, "write2 at %lld %d bytes", (long long)offset, count);
Steve Frenchff7feac2005-11-15 16:45:16 -08002157
Steve French4c3130e2008-12-09 00:28:16 +00002158 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07002159 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00002160 } else {
Steve French8cc64c62005-10-03 13:49:43 -07002161 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00002162 if ((offset >> 32) > 0) {
2163 /* can not handle big offset for old srv */
2164 return -EIO;
2165 }
2166 }
Steve French8cc64c62005-10-03 13:49:43 -07002167 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002168 if (rc)
2169 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002170
2171 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
2172 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
2173
Linus Torvalds1da177e2005-04-16 15:20:36 -07002174 /* tcon and ses pointer are checked in smb_init */
2175 if (tcon->ses->server == NULL)
2176 return -ECONNABORTED;
2177
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002178 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002179 pSMB->Fid = netfid;
2180 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00002181 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002182 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002183 pSMB->Reserved = 0xFFFFFFFF;
2184 pSMB->WriteMode = 0;
2185 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002186
Linus Torvalds1da177e2005-04-16 15:20:36 -07002187 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00002188 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002189
Steve French3e844692005-10-03 13:37:24 -07002190 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
2191 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002192 /* header + 1 byte pad */
2193 smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
Steve French790fe572007-07-07 19:25:05 +00002194 if (wct == 14)
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002195 inc_rfc1001_len(pSMB, count + 1);
Steve French8cc64c62005-10-03 13:49:43 -07002196 else /* wct == 12 */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002197 inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
Steve French790fe572007-07-07 19:25:05 +00002198 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002199 pSMB->ByteCount = cpu_to_le16(count + 1);
2200 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00002201 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07002202 (struct smb_com_writex_req *)pSMB;
2203 pSMBW->ByteCount = cpu_to_le16(count + 5);
2204 }
Steve French3e844692005-10-03 13:37:24 -07002205 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00002206 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08002207 iov[0].iov_len = smb_hdr_len + 4;
2208 else /* wct == 12 pad bigger by four bytes */
2209 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00002210
Steve French3e844692005-10-03 13:37:24 -07002211
Steve Frenchec637e32005-12-12 20:53:18 -08002212 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French133672e2007-11-13 22:41:37 +00002213 long_op);
Steve Frencha4544342005-08-24 13:59:35 -07002214 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002215 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002216 cFYI(1, "Send error Write2 = %d", rc);
Steve French790fe572007-07-07 19:25:05 +00002217 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08002218 /* presumably this can not happen, but best to be safe */
2219 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002220 } else {
Steve Frenchad7a2922008-02-07 23:25:02 +00002221 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002222 *nbytes = le16_to_cpu(pSMBr->CountHigh);
2223 *nbytes = (*nbytes) << 16;
2224 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05302225
2226 /*
2227 * Mask off high 16 bits when bytes written as returned by the
2228 * server is greater than bytes requested by the client. OS/2
2229 * servers are known to set incorrect CountHigh values.
2230 */
2231 if (*nbytes > count)
2232 *nbytes &= 0xFFFF;
Steve French50c2f752007-07-13 00:33:32 +00002233 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002234
Steve French4b8f9302006-02-26 16:41:18 +00002235/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00002236 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002237 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00002238 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002239 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002240
Steve French50c2f752007-07-13 00:33:32 +00002241 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002242 since file handle passed in no longer valid */
2243
2244 return rc;
2245}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002246
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002247int cifs_lockv(const int xid, struct cifs_tcon *tcon, const __u16 netfid,
2248 const __u8 lock_type, const __u32 num_unlock,
2249 const __u32 num_lock, LOCKING_ANDX_RANGE *buf)
2250{
2251 int rc = 0;
2252 LOCK_REQ *pSMB = NULL;
2253 struct kvec iov[2];
2254 int resp_buf_type;
2255 __u16 count;
2256
2257 cFYI(1, "cifs_lockv num lock %d num unlock %d", num_lock, num_unlock);
2258
2259 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2260 if (rc)
2261 return rc;
2262
2263 pSMB->Timeout = 0;
2264 pSMB->NumberOfLocks = cpu_to_le16(num_lock);
2265 pSMB->NumberOfUnlocks = cpu_to_le16(num_unlock);
2266 pSMB->LockType = lock_type;
2267 pSMB->AndXCommand = 0xFF; /* none */
2268 pSMB->Fid = netfid; /* netfid stays le */
2269
2270 count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2271 inc_rfc1001_len(pSMB, count);
2272 pSMB->ByteCount = cpu_to_le16(count);
2273
2274 iov[0].iov_base = (char *)pSMB;
2275 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 -
2276 (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2277 iov[1].iov_base = (char *)buf;
2278 iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2279
2280 cifs_stats_inc(&tcon->num_locks);
2281 rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP);
2282 if (rc)
2283 cFYI(1, "Send error in cifs_lockv = %d", rc);
2284
2285 return rc;
2286}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002287
Linus Torvalds1da177e2005-04-16 15:20:36 -07002288int
Steve French96daf2b2011-05-27 04:34:02 +00002289CIFSSMBLock(const int xid, struct cifs_tcon *tcon,
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002290 const __u16 smb_file_id, const __u32 netpid, const __u64 len,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002291 const __u64 offset, const __u32 numUnlock,
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002292 const __u32 numLock, const __u8 lockType,
2293 const bool waitFlag, const __u8 oplock_level)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002294{
2295 int rc = 0;
2296 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002297/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002298 int bytes_returned;
2299 int timeout = 0;
2300 __u16 count;
2301
Joe Perchesb6b38f72010-04-21 03:50:45 +00002302 cFYI(1, "CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock);
Steve French46810cb2005-04-28 22:41:09 -07002303 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2304
Linus Torvalds1da177e2005-04-16 15:20:36 -07002305 if (rc)
2306 return rc;
2307
Steve French790fe572007-07-07 19:25:05 +00002308 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Steve French133672e2007-11-13 22:41:37 +00002309 timeout = CIFS_ASYNC_OP; /* no response expected */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00002311 } else if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00002312 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002313 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
2314 } else {
2315 pSMB->Timeout = 0;
2316 }
2317
2318 pSMB->NumberOfLocks = cpu_to_le16(numLock);
2319 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
2320 pSMB->LockType = lockType;
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002321 pSMB->OplockLevel = oplock_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002322 pSMB->AndXCommand = 0xFF; /* none */
2323 pSMB->Fid = smb_file_id; /* netfid stays le */
2324
Steve French790fe572007-07-07 19:25:05 +00002325 if ((numLock != 0) || (numUnlock != 0)) {
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002326 pSMB->Locks[0].Pid = cpu_to_le16(netpid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002327 /* BB where to store pid high? */
2328 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
2329 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
2330 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
2331 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
2332 count = sizeof(LOCKING_ANDX_RANGE);
2333 } else {
2334 /* oplock break */
2335 count = 0;
2336 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002337 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002338 pSMB->ByteCount = cpu_to_le16(count);
2339
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002340 if (waitFlag) {
2341 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002342 (struct smb_hdr *) pSMB, &bytes_returned);
Steve French133672e2007-11-13 22:41:37 +00002343 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002344 } else {
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002345 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, timeout);
Steve French133672e2007-11-13 22:41:37 +00002346 /* SMB buffer freed by function above */
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002347 }
Steve Frencha4544342005-08-24 13:59:35 -07002348 cifs_stats_inc(&tcon->num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002349 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002350 cFYI(1, "Send error in Lock = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002351
Steve French50c2f752007-07-13 00:33:32 +00002352 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002353 since file handle passed in no longer valid */
2354 return rc;
2355}
2356
2357int
Steve French96daf2b2011-05-27 04:34:02 +00002358CIFSSMBPosixLock(const int xid, struct cifs_tcon *tcon,
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002359 const __u16 smb_file_id, const __u32 netpid,
2360 const loff_t start_offset, const __u64 len,
2361 struct file_lock *pLockData, const __u16 lock_type,
2362 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00002363{
2364 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2365 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00002366 struct cifs_posix_lock *parm_data;
2367 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00002368 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00002369 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00002370 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00002371 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00002372 struct kvec iov[1];
Steve French08547b02006-02-28 22:39:25 +00002373
Joe Perchesb6b38f72010-04-21 03:50:45 +00002374 cFYI(1, "Posix Lock");
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002375
Steve French08547b02006-02-28 22:39:25 +00002376 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
2377
2378 if (rc)
2379 return rc;
2380
2381 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
2382
Steve French50c2f752007-07-13 00:33:32 +00002383 params = 6;
Steve French08547b02006-02-28 22:39:25 +00002384 pSMB->MaxSetupCount = 0;
2385 pSMB->Reserved = 0;
2386 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00002387 pSMB->Reserved2 = 0;
2388 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2389 offset = param_offset + params;
2390
Steve French08547b02006-02-28 22:39:25 +00002391 count = sizeof(struct cifs_posix_lock);
2392 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002393 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00002394 pSMB->SetupCount = 1;
2395 pSMB->Reserved3 = 0;
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002396 if (pLockData)
Steve French08547b02006-02-28 22:39:25 +00002397 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2398 else
2399 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2400 byte_count = 3 /* pad */ + params + count;
2401 pSMB->DataCount = cpu_to_le16(count);
2402 pSMB->ParameterCount = cpu_to_le16(params);
2403 pSMB->TotalDataCount = pSMB->DataCount;
2404 pSMB->TotalParameterCount = pSMB->ParameterCount;
2405 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00002406 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00002407 (((char *) &pSMB->hdr.Protocol) + offset);
2408
2409 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00002410 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00002411 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00002412 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00002413 pSMB->Timeout = cpu_to_le32(-1);
2414 } else
2415 pSMB->Timeout = 0;
2416
Pavel Shilovsky4f6bcec2011-10-22 15:33:30 +04002417 parm_data->pid = cpu_to_le32(netpid);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002418 parm_data->start = cpu_to_le64(start_offset);
Steve Frenchcec6815a2006-05-30 18:07:17 +00002419 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00002420
2421 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00002422 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00002423 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
2424 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002425 inc_rfc1001_len(pSMB, byte_count);
Steve French08547b02006-02-28 22:39:25 +00002426 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002427 if (waitFlag) {
2428 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2429 (struct smb_hdr *) pSMBr, &bytes_returned);
2430 } else {
Steve French133672e2007-11-13 22:41:37 +00002431 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002432 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French133672e2007-11-13 22:41:37 +00002433 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
2434 &resp_buf_type, timeout);
2435 pSMB = NULL; /* request buf already freed by SendReceive2. Do
2436 not try to free it twice below on exit */
2437 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002438 }
2439
Steve French08547b02006-02-28 22:39:25 +00002440 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002441 cFYI(1, "Send error in Posix Lock = %d", rc);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002442 } else if (pLockData) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002443 /* lock structure can be returned on get */
2444 __u16 data_offset;
2445 __u16 data_count;
2446 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00002447
Jeff Layton820a8032011-05-04 08:05:26 -04002448 if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002449 rc = -EIO; /* bad smb */
2450 goto plk_err_exit;
2451 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002452 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2453 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00002454 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002455 rc = -EIO;
2456 goto plk_err_exit;
2457 }
2458 parm_data = (struct cifs_posix_lock *)
2459 ((char *)&pSMBr->hdr.Protocol + data_offset);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002460 if (parm_data->lock_type == __constant_cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002461 pLockData->fl_type = F_UNLCK;
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002462 else {
2463 if (parm_data->lock_type ==
2464 __constant_cpu_to_le16(CIFS_RDLCK))
2465 pLockData->fl_type = F_RDLCK;
2466 else if (parm_data->lock_type ==
2467 __constant_cpu_to_le16(CIFS_WRLCK))
2468 pLockData->fl_type = F_WRLCK;
2469
Steve French5443d132011-03-13 05:08:25 +00002470 pLockData->fl_start = le64_to_cpu(parm_data->start);
2471 pLockData->fl_end = pLockData->fl_start +
2472 le64_to_cpu(parm_data->length) - 1;
2473 pLockData->fl_pid = le32_to_cpu(parm_data->pid);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002474 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002475 }
Steve French50c2f752007-07-13 00:33:32 +00002476
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002477plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00002478 if (pSMB)
2479 cifs_small_buf_release(pSMB);
2480
Steve French133672e2007-11-13 22:41:37 +00002481 if (resp_buf_type == CIFS_SMALL_BUFFER)
2482 cifs_small_buf_release(iov[0].iov_base);
2483 else if (resp_buf_type == CIFS_LARGE_BUFFER)
2484 cifs_buf_release(iov[0].iov_base);
2485
Steve French08547b02006-02-28 22:39:25 +00002486 /* Note: On -EAGAIN error only caller can retry on handle based calls
2487 since file handle passed in no longer valid */
2488
2489 return rc;
2490}
2491
2492
2493int
Steve French96daf2b2011-05-27 04:34:02 +00002494CIFSSMBClose(const int xid, struct cifs_tcon *tcon, int smb_file_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002495{
2496 int rc = 0;
2497 CLOSE_REQ *pSMB = NULL;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002498 cFYI(1, "In CIFSSMBClose");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002499
2500/* do not retry on dead session on close */
2501 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00002502 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002503 return 0;
2504 if (rc)
2505 return rc;
2506
Linus Torvalds1da177e2005-04-16 15:20:36 -07002507 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00002508 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002509 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002510 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002511 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002512 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00002513 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002514 /* EINTR is expected when user ctl-c to kill app */
Joe Perchesb6b38f72010-04-21 03:50:45 +00002515 cERROR(1, "Send error in Close = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002516 }
2517 }
2518
Linus Torvalds1da177e2005-04-16 15:20:36 -07002519 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00002520 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002521 rc = 0;
2522
2523 return rc;
2524}
2525
2526int
Steve French96daf2b2011-05-27 04:34:02 +00002527CIFSSMBFlush(const int xid, struct cifs_tcon *tcon, int smb_file_id)
Steve Frenchb298f222009-02-21 21:17:43 +00002528{
2529 int rc = 0;
2530 FLUSH_REQ *pSMB = NULL;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002531 cFYI(1, "In CIFSSMBFlush");
Steve Frenchb298f222009-02-21 21:17:43 +00002532
2533 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
2534 if (rc)
2535 return rc;
2536
2537 pSMB->FileID = (__u16) smb_file_id;
2538 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002539 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frenchb298f222009-02-21 21:17:43 +00002540 cifs_stats_inc(&tcon->num_flushes);
2541 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002542 cERROR(1, "Send error in Flush = %d", rc);
Steve Frenchb298f222009-02-21 21:17:43 +00002543
2544 return rc;
2545}
2546
2547int
Steve French96daf2b2011-05-27 04:34:02 +00002548CIFSSMBRename(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002549 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002550 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002551{
2552 int rc = 0;
2553 RENAME_REQ *pSMB = NULL;
2554 RENAME_RSP *pSMBr = NULL;
2555 int bytes_returned;
2556 int name_len, name_len2;
2557 __u16 count;
2558
Joe Perchesb6b38f72010-04-21 03:50:45 +00002559 cFYI(1, "In CIFSSMBRename");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002560renameRetry:
2561 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
2562 (void **) &pSMBr);
2563 if (rc)
2564 return rc;
2565
2566 pSMB->BufferFormat = 0x04;
2567 pSMB->SearchAttributes =
2568 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2569 ATTR_DIRECTORY);
2570
2571 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2572 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06002573 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, fromName,
2574 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002575 name_len++; /* trailing null */
2576 name_len *= 2;
2577 pSMB->OldFileName[name_len] = 0x04; /* pad */
2578 /* protocol requires ASCII signature byte on Unicode string */
2579 pSMB->OldFileName[name_len + 1] = 0x00;
2580 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002581 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2582 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002583 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2584 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002585 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002586 name_len = strnlen(fromName, PATH_MAX);
2587 name_len++; /* trailing null */
2588 strncpy(pSMB->OldFileName, fromName, name_len);
2589 name_len2 = strnlen(toName, PATH_MAX);
2590 name_len2++; /* trailing null */
2591 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2592 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2593 name_len2++; /* trailing null */
2594 name_len2++; /* signature byte */
2595 }
2596
2597 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002598 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002599 pSMB->ByteCount = cpu_to_le16(count);
2600
2601 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2602 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002603 cifs_stats_inc(&tcon->num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002604 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002605 cFYI(1, "Send error in rename = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002606
Linus Torvalds1da177e2005-04-16 15:20:36 -07002607 cifs_buf_release(pSMB);
2608
2609 if (rc == -EAGAIN)
2610 goto renameRetry;
2611
2612 return rc;
2613}
2614
Steve French96daf2b2011-05-27 04:34:02 +00002615int CIFSSMBRenameOpenFile(const int xid, struct cifs_tcon *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002616 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002617 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002618{
2619 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2620 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002621 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002622 char *data_offset;
2623 char dummy_string[30];
2624 int rc = 0;
2625 int bytes_returned = 0;
2626 int len_of_str;
2627 __u16 params, param_offset, offset, count, byte_count;
2628
Joe Perchesb6b38f72010-04-21 03:50:45 +00002629 cFYI(1, "Rename to File by handle");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002630 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2631 (void **) &pSMBr);
2632 if (rc)
2633 return rc;
2634
2635 params = 6;
2636 pSMB->MaxSetupCount = 0;
2637 pSMB->Reserved = 0;
2638 pSMB->Flags = 0;
2639 pSMB->Timeout = 0;
2640 pSMB->Reserved2 = 0;
2641 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2642 offset = param_offset + params;
2643
2644 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2645 rename_info = (struct set_file_rename *) data_offset;
2646 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002647 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002648 pSMB->SetupCount = 1;
2649 pSMB->Reserved3 = 0;
2650 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2651 byte_count = 3 /* pad */ + params;
2652 pSMB->ParameterCount = cpu_to_le16(params);
2653 pSMB->TotalParameterCount = pSMB->ParameterCount;
2654 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2655 pSMB->DataOffset = cpu_to_le16(offset);
2656 /* construct random name ".cifs_tmp<inodenum><mid>" */
2657 rename_info->overwrite = cpu_to_le32(1);
2658 rename_info->root_fid = 0;
2659 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002660 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002661 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
Steve Frenchacbbb762012-01-18 22:32:33 -06002662 len_of_str =
2663 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002664 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002665 } else {
Steve Frenchacbbb762012-01-18 22:32:33 -06002666 len_of_str =
2667 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002668 target_name, PATH_MAX, nls_codepage,
2669 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002670 }
2671 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002672 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002673 byte_count += count;
2674 pSMB->DataCount = cpu_to_le16(count);
2675 pSMB->TotalDataCount = pSMB->DataCount;
2676 pSMB->Fid = netfid;
2677 pSMB->InformationLevel =
2678 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2679 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002680 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002681 pSMB->ByteCount = cpu_to_le16(byte_count);
2682 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002683 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002684 cifs_stats_inc(&pTcon->num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002685 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002686 cFYI(1, "Send error in Rename (by file handle) = %d", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07002687
Linus Torvalds1da177e2005-04-16 15:20:36 -07002688 cifs_buf_release(pSMB);
2689
2690 /* Note: On -EAGAIN error only caller can retry on handle based calls
2691 since file handle passed in no longer valid */
2692
2693 return rc;
2694}
2695
2696int
Steve French96daf2b2011-05-27 04:34:02 +00002697CIFSSMBCopy(const int xid, struct cifs_tcon *tcon, const char *fromName,
Steve French50c2f752007-07-13 00:33:32 +00002698 const __u16 target_tid, const char *toName, const int flags,
2699 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002700{
2701 int rc = 0;
2702 COPY_REQ *pSMB = NULL;
2703 COPY_RSP *pSMBr = NULL;
2704 int bytes_returned;
2705 int name_len, name_len2;
2706 __u16 count;
2707
Joe Perchesb6b38f72010-04-21 03:50:45 +00002708 cFYI(1, "In CIFSSMBCopy");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002709copyRetry:
2710 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2711 (void **) &pSMBr);
2712 if (rc)
2713 return rc;
2714
2715 pSMB->BufferFormat = 0x04;
2716 pSMB->Tid2 = target_tid;
2717
2718 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2719
2720 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002721 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2722 fromName, PATH_MAX, nls_codepage,
2723 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002724 name_len++; /* trailing null */
2725 name_len *= 2;
2726 pSMB->OldFileName[name_len] = 0x04; /* pad */
2727 /* protocol requires ASCII signature byte on Unicode string */
2728 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002729 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002730 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2731 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002732 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2733 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002734 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735 name_len = strnlen(fromName, PATH_MAX);
2736 name_len++; /* trailing null */
2737 strncpy(pSMB->OldFileName, fromName, name_len);
2738 name_len2 = strnlen(toName, PATH_MAX);
2739 name_len2++; /* trailing null */
2740 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2741 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2742 name_len2++; /* trailing null */
2743 name_len2++; /* signature byte */
2744 }
2745
2746 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002747 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748 pSMB->ByteCount = cpu_to_le16(count);
2749
2750 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2751 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2752 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002753 cFYI(1, "Send error in copy = %d with %d files copied",
2754 rc, le16_to_cpu(pSMBr->CopyCount));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002755 }
Steve French0d817bc2008-05-22 02:02:03 +00002756 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002757
2758 if (rc == -EAGAIN)
2759 goto copyRetry;
2760
2761 return rc;
2762}
2763
2764int
Steve French96daf2b2011-05-27 04:34:02 +00002765CIFSUnixCreateSymLink(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002766 const char *fromName, const char *toName,
2767 const struct nls_table *nls_codepage)
2768{
2769 TRANSACTION2_SPI_REQ *pSMB = NULL;
2770 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2771 char *data_offset;
2772 int name_len;
2773 int name_len_target;
2774 int rc = 0;
2775 int bytes_returned = 0;
2776 __u16 params, param_offset, offset, byte_count;
2777
Joe Perchesb6b38f72010-04-21 03:50:45 +00002778 cFYI(1, "In Symlink Unix style");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002779createSymLinkRetry:
2780 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2781 (void **) &pSMBr);
2782 if (rc)
2783 return rc;
2784
2785 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2786 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06002787 cifs_strtoUTF16((__le16 *) pSMB->FileName, fromName,
2788 /* find define for this maxpathcomponent */
2789 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002790 name_len++; /* trailing null */
2791 name_len *= 2;
2792
Steve French50c2f752007-07-13 00:33:32 +00002793 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002794 name_len = strnlen(fromName, PATH_MAX);
2795 name_len++; /* trailing null */
2796 strncpy(pSMB->FileName, fromName, name_len);
2797 }
2798 params = 6 + name_len;
2799 pSMB->MaxSetupCount = 0;
2800 pSMB->Reserved = 0;
2801 pSMB->Flags = 0;
2802 pSMB->Timeout = 0;
2803 pSMB->Reserved2 = 0;
2804 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002805 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002806 offset = param_offset + params;
2807
2808 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2809 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2810 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06002811 cifs_strtoUTF16((__le16 *) data_offset, toName, PATH_MAX
2812 /* find define for this maxpathcomponent */
2813 , nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002814 name_len_target++; /* trailing null */
2815 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002816 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002817 name_len_target = strnlen(toName, PATH_MAX);
2818 name_len_target++; /* trailing null */
2819 strncpy(data_offset, toName, name_len_target);
2820 }
2821
2822 pSMB->MaxParameterCount = cpu_to_le16(2);
2823 /* BB find exact max on data count below from sess */
2824 pSMB->MaxDataCount = cpu_to_le16(1000);
2825 pSMB->SetupCount = 1;
2826 pSMB->Reserved3 = 0;
2827 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2828 byte_count = 3 /* pad */ + params + name_len_target;
2829 pSMB->DataCount = cpu_to_le16(name_len_target);
2830 pSMB->ParameterCount = cpu_to_le16(params);
2831 pSMB->TotalDataCount = pSMB->DataCount;
2832 pSMB->TotalParameterCount = pSMB->ParameterCount;
2833 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2834 pSMB->DataOffset = cpu_to_le16(offset);
2835 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2836 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002837 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002838 pSMB->ByteCount = cpu_to_le16(byte_count);
2839 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2840 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002841 cifs_stats_inc(&tcon->num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002842 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002843 cFYI(1, "Send error in SetPathInfo create symlink = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002844
Steve French0d817bc2008-05-22 02:02:03 +00002845 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002846
2847 if (rc == -EAGAIN)
2848 goto createSymLinkRetry;
2849
2850 return rc;
2851}
2852
2853int
Steve French96daf2b2011-05-27 04:34:02 +00002854CIFSUnixCreateHardLink(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002855 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002856 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002857{
2858 TRANSACTION2_SPI_REQ *pSMB = NULL;
2859 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2860 char *data_offset;
2861 int name_len;
2862 int name_len_target;
2863 int rc = 0;
2864 int bytes_returned = 0;
2865 __u16 params, param_offset, offset, byte_count;
2866
Joe Perchesb6b38f72010-04-21 03:50:45 +00002867 cFYI(1, "In Create Hard link Unix style");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002868createHardLinkRetry:
2869 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2870 (void **) &pSMBr);
2871 if (rc)
2872 return rc;
2873
2874 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002875 name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, toName,
2876 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002877 name_len++; /* trailing null */
2878 name_len *= 2;
2879
Steve French50c2f752007-07-13 00:33:32 +00002880 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002881 name_len = strnlen(toName, PATH_MAX);
2882 name_len++; /* trailing null */
2883 strncpy(pSMB->FileName, toName, name_len);
2884 }
2885 params = 6 + name_len;
2886 pSMB->MaxSetupCount = 0;
2887 pSMB->Reserved = 0;
2888 pSMB->Flags = 0;
2889 pSMB->Timeout = 0;
2890 pSMB->Reserved2 = 0;
2891 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002892 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002893 offset = param_offset + params;
2894
2895 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2896 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2897 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06002898 cifsConvertToUTF16((__le16 *) data_offset, fromName,
2899 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002900 name_len_target++; /* trailing null */
2901 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002902 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002903 name_len_target = strnlen(fromName, PATH_MAX);
2904 name_len_target++; /* trailing null */
2905 strncpy(data_offset, fromName, name_len_target);
2906 }
2907
2908 pSMB->MaxParameterCount = cpu_to_le16(2);
2909 /* BB find exact max on data count below from sess*/
2910 pSMB->MaxDataCount = cpu_to_le16(1000);
2911 pSMB->SetupCount = 1;
2912 pSMB->Reserved3 = 0;
2913 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2914 byte_count = 3 /* pad */ + params + name_len_target;
2915 pSMB->ParameterCount = cpu_to_le16(params);
2916 pSMB->TotalParameterCount = pSMB->ParameterCount;
2917 pSMB->DataCount = cpu_to_le16(name_len_target);
2918 pSMB->TotalDataCount = pSMB->DataCount;
2919 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2920 pSMB->DataOffset = cpu_to_le16(offset);
2921 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2922 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002923 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002924 pSMB->ByteCount = cpu_to_le16(byte_count);
2925 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2926 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002927 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002928 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002929 cFYI(1, "Send error in SetPathInfo (hard link) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002930
2931 cifs_buf_release(pSMB);
2932 if (rc == -EAGAIN)
2933 goto createHardLinkRetry;
2934
2935 return rc;
2936}
2937
2938int
Steve French96daf2b2011-05-27 04:34:02 +00002939CIFSCreateHardLink(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002940 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002941 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002942{
2943 int rc = 0;
2944 NT_RENAME_REQ *pSMB = NULL;
2945 RENAME_RSP *pSMBr = NULL;
2946 int bytes_returned;
2947 int name_len, name_len2;
2948 __u16 count;
2949
Joe Perchesb6b38f72010-04-21 03:50:45 +00002950 cFYI(1, "In CIFSCreateHardLink");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002951winCreateHardLinkRetry:
2952
2953 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2954 (void **) &pSMBr);
2955 if (rc)
2956 return rc;
2957
2958 pSMB->SearchAttributes =
2959 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2960 ATTR_DIRECTORY);
2961 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2962 pSMB->ClusterCount = 0;
2963
2964 pSMB->BufferFormat = 0x04;
2965
2966 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2967 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06002968 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, fromName,
2969 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002970 name_len++; /* trailing null */
2971 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05002972
2973 /* protocol specifies ASCII buffer format (0x04) for unicode */
2974 pSMB->OldFileName[name_len] = 0x04;
2975 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002976 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002977 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2978 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002979 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2980 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002981 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002982 name_len = strnlen(fromName, PATH_MAX);
2983 name_len++; /* trailing null */
2984 strncpy(pSMB->OldFileName, fromName, name_len);
2985 name_len2 = strnlen(toName, PATH_MAX);
2986 name_len2++; /* trailing null */
2987 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2988 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2989 name_len2++; /* trailing null */
2990 name_len2++; /* signature byte */
2991 }
2992
2993 count = 1 /* string type byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002994 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002995 pSMB->ByteCount = cpu_to_le16(count);
2996
2997 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2998 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002999 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00003000 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003001 cFYI(1, "Send error in hard link (NT rename) = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00003002
Linus Torvalds1da177e2005-04-16 15:20:36 -07003003 cifs_buf_release(pSMB);
3004 if (rc == -EAGAIN)
3005 goto winCreateHardLinkRetry;
3006
3007 return rc;
3008}
3009
3010int
Steve French96daf2b2011-05-27 04:34:02 +00003011CIFSSMBUnixQuerySymLink(const int xid, struct cifs_tcon *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04003012 const unsigned char *searchName, char **symlinkinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003013 const struct nls_table *nls_codepage)
3014{
3015/* SMB_QUERY_FILE_UNIX_LINK */
3016 TRANSACTION2_QPI_REQ *pSMB = NULL;
3017 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3018 int rc = 0;
3019 int bytes_returned;
3020 int name_len;
3021 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04003022 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003023
Joe Perchesb6b38f72010-04-21 03:50:45 +00003024 cFYI(1, "In QPathSymLinkInfo (Unix) for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003025
3026querySymLinkRetry:
3027 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3028 (void **) &pSMBr);
3029 if (rc)
3030 return rc;
3031
3032 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3033 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003034 cifs_strtoUTF16((__le16 *) pSMB->FileName, searchName,
3035 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003036 name_len++; /* trailing null */
3037 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003038 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003039 name_len = strnlen(searchName, PATH_MAX);
3040 name_len++; /* trailing null */
3041 strncpy(pSMB->FileName, searchName, name_len);
3042 }
3043
3044 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3045 pSMB->TotalDataCount = 0;
3046 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04003047 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003048 pSMB->MaxSetupCount = 0;
3049 pSMB->Reserved = 0;
3050 pSMB->Flags = 0;
3051 pSMB->Timeout = 0;
3052 pSMB->Reserved2 = 0;
3053 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003054 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003055 pSMB->DataCount = 0;
3056 pSMB->DataOffset = 0;
3057 pSMB->SetupCount = 1;
3058 pSMB->Reserved3 = 0;
3059 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3060 byte_count = params + 1 /* pad */ ;
3061 pSMB->TotalParameterCount = cpu_to_le16(params);
3062 pSMB->ParameterCount = pSMB->TotalParameterCount;
3063 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
3064 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003065 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003066 pSMB->ByteCount = cpu_to_le16(byte_count);
3067
3068 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3069 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3070 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003071 cFYI(1, "Send error in QuerySymLinkInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003072 } else {
3073 /* decode response */
3074
3075 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003076 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003077 if (rc || get_bcc(&pSMBr->hdr) < 2)
Jeff Layton460b9692009-04-30 07:17:56 -04003078 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003079 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00003080 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04003081 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003082
Jeff Layton460b9692009-04-30 07:17:56 -04003083 data_start = ((char *) &pSMBr->hdr.Protocol) +
3084 le16_to_cpu(pSMBr->t2.DataOffset);
3085
Steve French0e0d2cf2009-05-01 05:27:32 +00003086 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3087 is_unicode = true;
3088 else
3089 is_unicode = false;
3090
Steve French737b7582005-04-28 22:41:06 -07003091 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchacbbb762012-01-18 22:32:33 -06003092 *symlinkinfo = cifs_strndup_from_utf16(data_start,
3093 count, is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04003094 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04003095 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003096 }
3097 }
3098 cifs_buf_release(pSMB);
3099 if (rc == -EAGAIN)
3100 goto querySymLinkRetry;
3101 return rc;
3102}
3103
Steve Frenchc52a9552011-02-24 06:16:22 +00003104#ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL
3105/*
3106 * Recent Windows versions now create symlinks more frequently
3107 * and they use the "reparse point" mechanism below. We can of course
3108 * do symlinks nicely to Samba and other servers which support the
3109 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
3110 * "MF" symlinks optionally, but for recent Windows we really need to
3111 * reenable the code below and fix the cifs_symlink callers to handle this.
3112 * In the interim this code has been moved to its own config option so
3113 * it is not compiled in by default until callers fixed up and more tested.
3114 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003115int
Steve French96daf2b2011-05-27 04:34:02 +00003116CIFSSMBQueryReparseLinkInfo(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003117 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00003118 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003119 const struct nls_table *nls_codepage)
3120{
3121 int rc = 0;
3122 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00003123 struct smb_com_transaction_ioctl_req *pSMB;
3124 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003125
Joe Perchesb6b38f72010-04-21 03:50:45 +00003126 cFYI(1, "In Windows reparse style QueryLink for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003127 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3128 (void **) &pSMBr);
3129 if (rc)
3130 return rc;
3131
3132 pSMB->TotalParameterCount = 0 ;
3133 pSMB->TotalDataCount = 0;
3134 pSMB->MaxParameterCount = cpu_to_le32(2);
3135 /* BB find exact data count max from sess structure BB */
Jeff Laytonc974bef2011-10-11 06:41:32 -04003136 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003137 pSMB->MaxSetupCount = 4;
3138 pSMB->Reserved = 0;
3139 pSMB->ParameterOffset = 0;
3140 pSMB->DataCount = 0;
3141 pSMB->DataOffset = 0;
3142 pSMB->SetupCount = 4;
3143 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
3144 pSMB->ParameterCount = pSMB->TotalParameterCount;
3145 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
3146 pSMB->IsFsctl = 1; /* FSCTL */
3147 pSMB->IsRootFlag = 0;
3148 pSMB->Fid = fid; /* file handle always le */
3149 pSMB->ByteCount = 0;
3150
3151 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3152 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3153 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003154 cFYI(1, "Send error in QueryReparseLinkInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003155 } else { /* decode response */
3156 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
3157 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
Jeff Layton820a8032011-05-04 08:05:26 -04003158 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
3159 /* BB also check enough total bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003160 rc = -EIO; /* bad smb */
Steve Frenchafe48c32009-05-02 05:25:46 +00003161 goto qreparse_out;
3162 }
3163 if (data_count && (data_count < 2048)) {
3164 char *end_of_smb = 2 /* sizeof byte count */ +
Jeff Layton820a8032011-05-04 08:05:26 -04003165 get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003166
Steve Frenchafe48c32009-05-02 05:25:46 +00003167 struct reparse_data *reparse_buf =
Steve French50c2f752007-07-13 00:33:32 +00003168 (struct reparse_data *)
3169 ((char *)&pSMBr->hdr.Protocol
3170 + data_offset);
Steve Frenchafe48c32009-05-02 05:25:46 +00003171 if ((char *)reparse_buf >= end_of_smb) {
3172 rc = -EIO;
3173 goto qreparse_out;
3174 }
3175 if ((reparse_buf->LinkNamesBuf +
3176 reparse_buf->TargetNameOffset +
3177 reparse_buf->TargetNameLen) > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003178 cFYI(1, "reparse buf beyond SMB");
Steve Frenchafe48c32009-05-02 05:25:46 +00003179 rc = -EIO;
3180 goto qreparse_out;
3181 }
Steve French50c2f752007-07-13 00:33:32 +00003182
Steve Frenchafe48c32009-05-02 05:25:46 +00003183 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3184 cifs_from_ucs2(symlinkinfo, (__le16 *)
Steve French50c2f752007-07-13 00:33:32 +00003185 (reparse_buf->LinkNamesBuf +
3186 reparse_buf->TargetNameOffset),
Steve Frenchafe48c32009-05-02 05:25:46 +00003187 buflen,
3188 reparse_buf->TargetNameLen,
3189 nls_codepage, 0);
3190 } else { /* ASCII names */
3191 strncpy(symlinkinfo,
3192 reparse_buf->LinkNamesBuf +
3193 reparse_buf->TargetNameOffset,
3194 min_t(const int, buflen,
3195 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003196 }
Steve Frenchafe48c32009-05-02 05:25:46 +00003197 } else {
3198 rc = -EIO;
Joe Perchesb6b38f72010-04-21 03:50:45 +00003199 cFYI(1, "Invalid return data count on "
3200 "get reparse info ioctl");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003201 }
Steve Frenchafe48c32009-05-02 05:25:46 +00003202 symlinkinfo[buflen] = 0; /* just in case so the caller
3203 does not go off the end of the buffer */
Joe Perchesb6b38f72010-04-21 03:50:45 +00003204 cFYI(1, "readlink result - %s", symlinkinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003205 }
Steve French989c7e52009-05-02 05:32:20 +00003206
Linus Torvalds1da177e2005-04-16 15:20:36 -07003207qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07003208 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003209
3210 /* Note: On -EAGAIN error only caller can retry on handle based calls
3211 since file handle passed in no longer valid */
3212
3213 return rc;
3214}
Steve Frenchc52a9552011-02-24 06:16:22 +00003215#endif /* CIFS_SYMLINK_EXPERIMENTAL */ /* BB temporarily unused */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003216
3217#ifdef CONFIG_CIFS_POSIX
3218
3219/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00003220static void cifs_convert_ace(posix_acl_xattr_entry *ace,
3221 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003222{
3223 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08003224 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
3225 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
3226 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesb6b38f72010-04-21 03:50:45 +00003227 /* cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003228
3229 return;
3230}
3231
3232/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00003233static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
3234 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003235{
3236 int size = 0;
3237 int i;
3238 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00003239 struct cifs_posix_ace *pACE;
3240 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
3241 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003242
3243 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
3244 return -EOPNOTSUPP;
3245
Steve French790fe572007-07-07 19:25:05 +00003246 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003247 count = le16_to_cpu(cifs_acl->access_entry_count);
3248 pACE = &cifs_acl->ace_array[0];
3249 size = sizeof(struct cifs_posix_acl);
3250 size += sizeof(struct cifs_posix_ace) * count;
3251 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003252 if (size_of_data_area < size) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003253 cFYI(1, "bad CIFS POSIX ACL size %d vs. %d",
3254 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003255 return -EINVAL;
3256 }
Steve French790fe572007-07-07 19:25:05 +00003257 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003258 count = le16_to_cpu(cifs_acl->access_entry_count);
3259 size = sizeof(struct cifs_posix_acl);
3260 size += sizeof(struct cifs_posix_ace) * count;
3261/* skip past access ACEs to get to default ACEs */
3262 pACE = &cifs_acl->ace_array[count];
3263 count = le16_to_cpu(cifs_acl->default_entry_count);
3264 size += sizeof(struct cifs_posix_ace) * count;
3265 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003266 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003267 return -EINVAL;
3268 } else {
3269 /* illegal type */
3270 return -EINVAL;
3271 }
3272
3273 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00003274 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00003275 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00003276 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003277 return -ERANGE;
3278 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08003279 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00003280 for (i = 0; i < count ; i++) {
3281 cifs_convert_ace(&local_acl->a_entries[i], pACE);
3282 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003283 }
3284 }
3285 return size;
3286}
3287
Steve French50c2f752007-07-13 00:33:32 +00003288static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
3289 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003290{
3291 __u16 rc = 0; /* 0 = ACL converted ok */
3292
Steve Frenchff7feac2005-11-15 16:45:16 -08003293 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
3294 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003295 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00003296 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003297 /* Probably no need to le convert -1 on any arch but can not hurt */
3298 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00003299 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08003300 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesb6b38f72010-04-21 03:50:45 +00003301 /*cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id);*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003302 return rc;
3303}
3304
3305/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00003306static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
3307 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003308{
3309 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00003310 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
3311 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003312 int count;
3313 int i;
3314
Steve French790fe572007-07-07 19:25:05 +00003315 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003316 return 0;
3317
3318 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesb6b38f72010-04-21 03:50:45 +00003319 cFYI(1, "setting acl with %d entries from buf of length %d and "
Steve French63135e02007-07-17 17:34:02 +00003320 "version of %d",
Joe Perchesb6b38f72010-04-21 03:50:45 +00003321 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00003322 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003323 cFYI(1, "unknown POSIX ACL version %d",
3324 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003325 return 0;
3326 }
3327 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00003328 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08003329 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00003330 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08003331 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003332 else {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003333 cFYI(1, "unknown ACL type %d", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003334 return 0;
3335 }
Steve French50c2f752007-07-13 00:33:32 +00003336 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003337 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
3338 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00003339 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003340 /* ACE not converted */
3341 break;
3342 }
3343 }
Steve French790fe572007-07-07 19:25:05 +00003344 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003345 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
3346 rc += sizeof(struct cifs_posix_acl);
3347 /* BB add check to make sure ACL does not overflow SMB */
3348 }
3349 return rc;
3350}
3351
3352int
Steve French96daf2b2011-05-27 04:34:02 +00003353CIFSSMBGetPosixACL(const int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003354 const unsigned char *searchName,
3355 char *acl_inf, const int buflen, const int acl_type,
3356 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003357{
3358/* SMB_QUERY_POSIX_ACL */
3359 TRANSACTION2_QPI_REQ *pSMB = NULL;
3360 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3361 int rc = 0;
3362 int bytes_returned;
3363 int name_len;
3364 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00003365
Joe Perchesb6b38f72010-04-21 03:50:45 +00003366 cFYI(1, "In GetPosixACL (Unix) for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003367
3368queryAclRetry:
3369 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3370 (void **) &pSMBr);
3371 if (rc)
3372 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003373
Linus Torvalds1da177e2005-04-16 15:20:36 -07003374 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3375 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003376 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3377 searchName, PATH_MAX, nls_codepage,
3378 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003379 name_len++; /* trailing null */
3380 name_len *= 2;
3381 pSMB->FileName[name_len] = 0;
3382 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00003383 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003384 name_len = strnlen(searchName, PATH_MAX);
3385 name_len++; /* trailing null */
3386 strncpy(pSMB->FileName, searchName, name_len);
3387 }
3388
3389 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3390 pSMB->TotalDataCount = 0;
3391 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00003392 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003393 pSMB->MaxDataCount = cpu_to_le16(4000);
3394 pSMB->MaxSetupCount = 0;
3395 pSMB->Reserved = 0;
3396 pSMB->Flags = 0;
3397 pSMB->Timeout = 0;
3398 pSMB->Reserved2 = 0;
3399 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003400 offsetof(struct smb_com_transaction2_qpi_req,
3401 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003402 pSMB->DataCount = 0;
3403 pSMB->DataOffset = 0;
3404 pSMB->SetupCount = 1;
3405 pSMB->Reserved3 = 0;
3406 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3407 byte_count = params + 1 /* pad */ ;
3408 pSMB->TotalParameterCount = cpu_to_le16(params);
3409 pSMB->ParameterCount = pSMB->TotalParameterCount;
3410 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
3411 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003412 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003413 pSMB->ByteCount = cpu_to_le16(byte_count);
3414
3415 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3416 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08003417 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003418 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003419 cFYI(1, "Send error in Query POSIX ACL = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003420 } else {
3421 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00003422
Linus Torvalds1da177e2005-04-16 15:20:36 -07003423 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003424 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003425 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003426 rc = -EIO; /* bad smb */
3427 else {
3428 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3429 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3430 rc = cifs_copy_posix_acl(acl_inf,
3431 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00003432 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003433 }
3434 }
3435 cifs_buf_release(pSMB);
3436 if (rc == -EAGAIN)
3437 goto queryAclRetry;
3438 return rc;
3439}
3440
3441int
Steve French96daf2b2011-05-27 04:34:02 +00003442CIFSSMBSetPosixACL(const int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003443 const unsigned char *fileName,
3444 const char *local_acl, const int buflen,
3445 const int acl_type,
3446 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003447{
3448 struct smb_com_transaction2_spi_req *pSMB = NULL;
3449 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3450 char *parm_data;
3451 int name_len;
3452 int rc = 0;
3453 int bytes_returned = 0;
3454 __u16 params, byte_count, data_count, param_offset, offset;
3455
Joe Perchesb6b38f72010-04-21 03:50:45 +00003456 cFYI(1, "In SetPosixACL (Unix) for path %s", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003457setAclRetry:
3458 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003459 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003460 if (rc)
3461 return rc;
3462 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3463 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003464 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
3465 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003466 name_len++; /* trailing null */
3467 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003468 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003469 name_len = strnlen(fileName, PATH_MAX);
3470 name_len++; /* trailing null */
3471 strncpy(pSMB->FileName, fileName, name_len);
3472 }
3473 params = 6 + name_len;
3474 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003475 /* BB find max SMB size from sess */
3476 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003477 pSMB->MaxSetupCount = 0;
3478 pSMB->Reserved = 0;
3479 pSMB->Flags = 0;
3480 pSMB->Timeout = 0;
3481 pSMB->Reserved2 = 0;
3482 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003483 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003484 offset = param_offset + params;
3485 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
3486 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3487
3488 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00003489 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003490
Steve French790fe572007-07-07 19:25:05 +00003491 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003492 rc = -EOPNOTSUPP;
3493 goto setACLerrorExit;
3494 }
3495 pSMB->DataOffset = cpu_to_le16(offset);
3496 pSMB->SetupCount = 1;
3497 pSMB->Reserved3 = 0;
3498 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3499 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
3500 byte_count = 3 /* pad */ + params + data_count;
3501 pSMB->DataCount = cpu_to_le16(data_count);
3502 pSMB->TotalDataCount = pSMB->DataCount;
3503 pSMB->ParameterCount = cpu_to_le16(params);
3504 pSMB->TotalParameterCount = pSMB->ParameterCount;
3505 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003506 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003507 pSMB->ByteCount = cpu_to_le16(byte_count);
3508 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003509 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003510 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003511 cFYI(1, "Set POSIX ACL returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003512
3513setACLerrorExit:
3514 cifs_buf_release(pSMB);
3515 if (rc == -EAGAIN)
3516 goto setAclRetry;
3517 return rc;
3518}
3519
Steve Frenchf654bac2005-04-28 22:41:04 -07003520/* BB fix tabs in this function FIXME BB */
3521int
Steve French96daf2b2011-05-27 04:34:02 +00003522CIFSGetExtAttr(const int xid, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00003523 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07003524{
Steve French50c2f752007-07-13 00:33:32 +00003525 int rc = 0;
3526 struct smb_t2_qfi_req *pSMB = NULL;
3527 struct smb_t2_qfi_rsp *pSMBr = NULL;
3528 int bytes_returned;
3529 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07003530
Joe Perchesb6b38f72010-04-21 03:50:45 +00003531 cFYI(1, "In GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00003532 if (tcon == NULL)
3533 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07003534
3535GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003536 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3537 (void **) &pSMBr);
3538 if (rc)
3539 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003540
Steve Frenchad7a2922008-02-07 23:25:02 +00003541 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003542 pSMB->t2.TotalDataCount = 0;
3543 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3544 /* BB find exact max data count below from sess structure BB */
3545 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3546 pSMB->t2.MaxSetupCount = 0;
3547 pSMB->t2.Reserved = 0;
3548 pSMB->t2.Flags = 0;
3549 pSMB->t2.Timeout = 0;
3550 pSMB->t2.Reserved2 = 0;
3551 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3552 Fid) - 4);
3553 pSMB->t2.DataCount = 0;
3554 pSMB->t2.DataOffset = 0;
3555 pSMB->t2.SetupCount = 1;
3556 pSMB->t2.Reserved3 = 0;
3557 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3558 byte_count = params + 1 /* pad */ ;
3559 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3560 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3561 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3562 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003563 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003564 inc_rfc1001_len(pSMB, byte_count);
Steve French790fe572007-07-07 19:25:05 +00003565 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003566
Steve French790fe572007-07-07 19:25:05 +00003567 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3568 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3569 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003570 cFYI(1, "error %d in GetExtAttr", rc);
Steve French790fe572007-07-07 19:25:05 +00003571 } else {
3572 /* decode response */
3573 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003574 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003575 if (rc || get_bcc(&pSMBr->hdr) < 2)
Steve French790fe572007-07-07 19:25:05 +00003576 /* If rc should we check for EOPNOSUPP and
3577 disable the srvino flag? or in caller? */
3578 rc = -EIO; /* bad smb */
3579 else {
3580 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3581 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3582 struct file_chattr_info *pfinfo;
3583 /* BB Do we need a cast or hash here ? */
3584 if (count != 16) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003585 cFYI(1, "Illegal size ret in GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00003586 rc = -EIO;
3587 goto GetExtAttrOut;
3588 }
3589 pfinfo = (struct file_chattr_info *)
3590 (data_offset + (char *) &pSMBr->hdr.Protocol);
3591 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003592 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003593 }
3594 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003595GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003596 cifs_buf_release(pSMB);
3597 if (rc == -EAGAIN)
3598 goto GetExtAttrRetry;
3599 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003600}
3601
Steve Frenchf654bac2005-04-28 22:41:04 -07003602#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003603
Jeff Layton79df1ba2010-12-06 12:52:08 -05003604#ifdef CONFIG_CIFS_ACL
3605/*
3606 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3607 * all NT TRANSACTS that we init here have total parm and data under about 400
3608 * bytes (to fit in small cifs buffer size), which is the case so far, it
3609 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3610 * returned setup area) and MaxParameterCount (returned parms size) must be set
3611 * by caller
3612 */
3613static int
3614smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French96daf2b2011-05-27 04:34:02 +00003615 const int parm_len, struct cifs_tcon *tcon,
Jeff Layton79df1ba2010-12-06 12:52:08 -05003616 void **ret_buf)
3617{
3618 int rc;
3619 __u32 temp_offset;
3620 struct smb_com_ntransact_req *pSMB;
3621
3622 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3623 (void **)&pSMB);
3624 if (rc)
3625 return rc;
3626 *ret_buf = (void *)pSMB;
3627 pSMB->Reserved = 0;
3628 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3629 pSMB->TotalDataCount = 0;
Jeff Laytonc974bef2011-10-11 06:41:32 -04003630 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003631 pSMB->ParameterCount = pSMB->TotalParameterCount;
3632 pSMB->DataCount = pSMB->TotalDataCount;
3633 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3634 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3635 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3636 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3637 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3638 pSMB->SubCommand = cpu_to_le16(sub_command);
3639 return 0;
3640}
3641
3642static int
3643validate_ntransact(char *buf, char **ppparm, char **ppdata,
3644 __u32 *pparmlen, __u32 *pdatalen)
3645{
3646 char *end_of_smb;
3647 __u32 data_count, data_offset, parm_count, parm_offset;
3648 struct smb_com_ntransact_rsp *pSMBr;
Jeff Layton820a8032011-05-04 08:05:26 -04003649 u16 bcc;
Jeff Layton79df1ba2010-12-06 12:52:08 -05003650
3651 *pdatalen = 0;
3652 *pparmlen = 0;
3653
3654 if (buf == NULL)
3655 return -EINVAL;
3656
3657 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3658
Jeff Layton820a8032011-05-04 08:05:26 -04003659 bcc = get_bcc(&pSMBr->hdr);
3660 end_of_smb = 2 /* sizeof byte count */ + bcc +
Jeff Layton79df1ba2010-12-06 12:52:08 -05003661 (char *)&pSMBr->ByteCount;
3662
3663 data_offset = le32_to_cpu(pSMBr->DataOffset);
3664 data_count = le32_to_cpu(pSMBr->DataCount);
3665 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3666 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3667
3668 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3669 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3670
3671 /* should we also check that parm and data areas do not overlap? */
3672 if (*ppparm > end_of_smb) {
3673 cFYI(1, "parms start after end of smb");
3674 return -EINVAL;
3675 } else if (parm_count + *ppparm > end_of_smb) {
3676 cFYI(1, "parm end after end of smb");
3677 return -EINVAL;
3678 } else if (*ppdata > end_of_smb) {
3679 cFYI(1, "data starts after end of smb");
3680 return -EINVAL;
3681 } else if (data_count + *ppdata > end_of_smb) {
3682 cFYI(1, "data %p + count %d (%p) past smb end %p start %p",
3683 *ppdata, data_count, (data_count + *ppdata),
3684 end_of_smb, pSMBr);
3685 return -EINVAL;
Jeff Layton820a8032011-05-04 08:05:26 -04003686 } else if (parm_count + data_count > bcc) {
Jeff Layton79df1ba2010-12-06 12:52:08 -05003687 cFYI(1, "parm count and data count larger than SMB");
3688 return -EINVAL;
3689 }
3690 *pdatalen = data_count;
3691 *pparmlen = parm_count;
3692 return 0;
3693}
3694
Steve French0a4b92c2006-01-12 15:44:21 -08003695/* Get Security Descriptor (by handle) from remote server for a file or dir */
3696int
Steve French96daf2b2011-05-27 04:34:02 +00003697CIFSSMBGetCIFSACL(const int xid, struct cifs_tcon *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003698 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003699{
3700 int rc = 0;
3701 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003702 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003703 struct kvec iov[1];
3704
Joe Perchesb6b38f72010-04-21 03:50:45 +00003705 cFYI(1, "GetCifsACL");
Steve French0a4b92c2006-01-12 15:44:21 -08003706
Steve French630f3f0c2007-10-25 21:17:17 +00003707 *pbuflen = 0;
3708 *acl_inf = NULL;
3709
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003710 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003711 8 /* parm len */, tcon, (void **) &pSMB);
3712 if (rc)
3713 return rc;
3714
3715 pSMB->MaxParameterCount = cpu_to_le32(4);
3716 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3717 pSMB->MaxSetupCount = 0;
3718 pSMB->Fid = fid; /* file handle always le */
3719 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3720 CIFS_ACL_DACL);
3721 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003722 inc_rfc1001_len(pSMB, 11);
Steve French0a4b92c2006-01-12 15:44:21 -08003723 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003724 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French0a4b92c2006-01-12 15:44:21 -08003725
Steve Frencha761ac52007-10-18 21:45:27 +00003726 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Jeff Layton77499812011-01-11 07:24:23 -05003727 0);
Steve French0a4b92c2006-01-12 15:44:21 -08003728 cifs_stats_inc(&tcon->num_acl_get);
3729 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003730 cFYI(1, "Send error in QuerySecDesc = %d", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08003731 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003732 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003733 __u32 parm_len;
3734 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003735 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003736 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003737
3738/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003739 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003740 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003741 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003742 goto qsec_out;
3743 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3744
Joe Perchesb6b38f72010-04-21 03:50:45 +00003745 cFYI(1, "smb %p parm %p data %p", pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08003746
3747 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3748 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003749 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003750 goto qsec_out;
3751 }
3752
3753/* BB check that data area is minimum length and as big as acl_len */
3754
Steve Frenchaf6f4612007-10-16 18:40:37 +00003755 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003756 if (acl_len != *pbuflen) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003757 cERROR(1, "acl length %d does not match %d",
3758 acl_len, *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003759 if (*pbuflen > acl_len)
3760 *pbuflen = acl_len;
3761 }
Steve French0a4b92c2006-01-12 15:44:21 -08003762
Steve French630f3f0c2007-10-25 21:17:17 +00003763 /* check if buffer is big enough for the acl
3764 header followed by the smallest SID */
3765 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3766 (*pbuflen >= 64 * 1024)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003767 cERROR(1, "bad acl length %d", *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003768 rc = -EINVAL;
3769 *pbuflen = 0;
3770 } else {
3771 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3772 if (*acl_inf == NULL) {
3773 *pbuflen = 0;
3774 rc = -ENOMEM;
3775 }
3776 memcpy(*acl_inf, pdata, *pbuflen);
3777 }
Steve French0a4b92c2006-01-12 15:44:21 -08003778 }
3779qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003780 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003781 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003782 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003783 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003784/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003785 return rc;
3786}
Steve French97837582007-12-31 07:47:21 +00003787
3788int
Steve French96daf2b2011-05-27 04:34:02 +00003789CIFSSMBSetCIFSACL(const int xid, struct cifs_tcon *tcon, __u16 fid,
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003790 struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
Steve French97837582007-12-31 07:47:21 +00003791{
3792 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3793 int rc = 0;
3794 int bytes_returned = 0;
3795 SET_SEC_DESC_REQ *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003796 void *pSMBr;
Steve French97837582007-12-31 07:47:21 +00003797
3798setCifsAclRetry:
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003799 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, &pSMBr);
Steve French97837582007-12-31 07:47:21 +00003800 if (rc)
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003801 return rc;
Steve French97837582007-12-31 07:47:21 +00003802
3803 pSMB->MaxSetupCount = 0;
3804 pSMB->Reserved = 0;
3805
3806 param_count = 8;
3807 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3808 data_count = acllen;
3809 data_offset = param_offset + param_count;
3810 byte_count = 3 /* pad */ + param_count;
3811
3812 pSMB->DataCount = cpu_to_le32(data_count);
3813 pSMB->TotalDataCount = pSMB->DataCount;
3814 pSMB->MaxParameterCount = cpu_to_le32(4);
3815 pSMB->MaxDataCount = cpu_to_le32(16384);
3816 pSMB->ParameterCount = cpu_to_le32(param_count);
3817 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3818 pSMB->TotalParameterCount = pSMB->ParameterCount;
3819 pSMB->DataOffset = cpu_to_le32(data_offset);
3820 pSMB->SetupCount = 0;
3821 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3822 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3823
3824 pSMB->Fid = fid; /* file handle always le */
3825 pSMB->Reserved2 = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003826 pSMB->AclFlags = cpu_to_le32(aclflag);
Steve French97837582007-12-31 07:47:21 +00003827
3828 if (pntsd && acllen) {
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003829 memcpy((char *)pSMBr + offsetof(struct smb_hdr, Protocol) +
3830 data_offset, pntsd, acllen);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003831 inc_rfc1001_len(pSMB, byte_count + data_count);
Steve French97837582007-12-31 07:47:21 +00003832 } else
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003833 inc_rfc1001_len(pSMB, byte_count);
Steve French97837582007-12-31 07:47:21 +00003834
3835 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3836 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3837
Joe Perchesb6b38f72010-04-21 03:50:45 +00003838 cFYI(1, "SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00003839 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003840 cFYI(1, "Set CIFS ACL returned %d", rc);
Steve French97837582007-12-31 07:47:21 +00003841 cifs_buf_release(pSMB);
3842
3843 if (rc == -EAGAIN)
3844 goto setCifsAclRetry;
3845
3846 return (rc);
3847}
3848
Jeff Layton79df1ba2010-12-06 12:52:08 -05003849#endif /* CONFIG_CIFS_ACL */
Steve French0a4b92c2006-01-12 15:44:21 -08003850
Steve French6b8edfe2005-08-23 20:26:03 -07003851/* Legacy Query Path Information call for lookup to old servers such
3852 as Win9x/WinME */
Steve French96daf2b2011-05-27 04:34:02 +00003853int SMBQueryInformation(const int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003854 const unsigned char *searchName,
3855 FILE_ALL_INFO *pFinfo,
3856 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003857{
Steve Frenchad7a2922008-02-07 23:25:02 +00003858 QUERY_INFORMATION_REQ *pSMB;
3859 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003860 int rc = 0;
3861 int bytes_returned;
3862 int name_len;
3863
Joe Perchesb6b38f72010-04-21 03:50:45 +00003864 cFYI(1, "In SMBQPath path %s", searchName);
Steve French6b8edfe2005-08-23 20:26:03 -07003865QInfRetry:
3866 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003867 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003868 if (rc)
3869 return rc;
3870
3871 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3872 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003873 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3874 searchName, PATH_MAX, nls_codepage,
3875 remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003876 name_len++; /* trailing null */
3877 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003878 } else {
Steve French6b8edfe2005-08-23 20:26:03 -07003879 name_len = strnlen(searchName, PATH_MAX);
3880 name_len++; /* trailing null */
3881 strncpy(pSMB->FileName, searchName, name_len);
3882 }
3883 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003884 name_len++; /* account for buffer type byte */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003885 inc_rfc1001_len(pSMB, (__u16)name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07003886 pSMB->ByteCount = cpu_to_le16(name_len);
3887
3888 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003889 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003890 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003891 cFYI(1, "Send error in QueryInfo = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00003892 } else if (pFinfo) {
Steve French1bd5bbc2006-09-28 03:35:57 +00003893 struct timespec ts;
3894 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00003895
3896 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003897 /* BB FIXME - add time zone adjustment BB */
Steve French6b8edfe2005-08-23 20:26:03 -07003898 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003899 ts.tv_nsec = 0;
3900 ts.tv_sec = time;
3901 /* decode time fields */
Al Viro733f99a2006-10-14 16:48:26 +01003902 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
Steve French1bd5bbc2006-09-28 03:35:57 +00003903 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3904 pFinfo->LastAccessTime = 0;
Steve French70ca7342005-09-22 16:32:06 -07003905 pFinfo->AllocationSize =
3906 cpu_to_le64(le32_to_cpu(pSMBr->size));
3907 pFinfo->EndOfFile = pFinfo->AllocationSize;
3908 pFinfo->Attributes =
3909 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003910 } else
3911 rc = -EIO; /* bad buffer passed in */
3912
3913 cifs_buf_release(pSMB);
3914
3915 if (rc == -EAGAIN)
3916 goto QInfRetry;
3917
3918 return rc;
3919}
3920
Jeff Laytonbcd53572010-02-12 07:44:16 -05003921int
Steve French96daf2b2011-05-27 04:34:02 +00003922CIFSSMBQFileInfo(const int xid, struct cifs_tcon *tcon,
Jeff Laytonbcd53572010-02-12 07:44:16 -05003923 u16 netfid, FILE_ALL_INFO *pFindData)
3924{
3925 struct smb_t2_qfi_req *pSMB = NULL;
3926 struct smb_t2_qfi_rsp *pSMBr = NULL;
3927 int rc = 0;
3928 int bytes_returned;
3929 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07003930
Jeff Laytonbcd53572010-02-12 07:44:16 -05003931QFileInfoRetry:
3932 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3933 (void **) &pSMBr);
3934 if (rc)
3935 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07003936
Jeff Laytonbcd53572010-02-12 07:44:16 -05003937 params = 2 /* level */ + 2 /* fid */;
3938 pSMB->t2.TotalDataCount = 0;
3939 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3940 /* BB find exact max data count below from sess structure BB */
3941 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3942 pSMB->t2.MaxSetupCount = 0;
3943 pSMB->t2.Reserved = 0;
3944 pSMB->t2.Flags = 0;
3945 pSMB->t2.Timeout = 0;
3946 pSMB->t2.Reserved2 = 0;
3947 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3948 Fid) - 4);
3949 pSMB->t2.DataCount = 0;
3950 pSMB->t2.DataOffset = 0;
3951 pSMB->t2.SetupCount = 1;
3952 pSMB->t2.Reserved3 = 0;
3953 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3954 byte_count = params + 1 /* pad */ ;
3955 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3956 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3957 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3958 pSMB->Pad = 0;
3959 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003960 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003961
3962 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3963 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3964 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00003965 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003966 } else { /* decode response */
3967 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3968
3969 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3970 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04003971 else if (get_bcc(&pSMBr->hdr) < 40)
Jeff Laytonbcd53572010-02-12 07:44:16 -05003972 rc = -EIO; /* bad smb */
3973 else if (pFindData) {
3974 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3975 memcpy((char *) pFindData,
3976 (char *) &pSMBr->hdr.Protocol +
3977 data_offset, sizeof(FILE_ALL_INFO));
3978 } else
3979 rc = -ENOMEM;
3980 }
3981 cifs_buf_release(pSMB);
3982 if (rc == -EAGAIN)
3983 goto QFileInfoRetry;
3984
3985 return rc;
3986}
Steve French6b8edfe2005-08-23 20:26:03 -07003987
Linus Torvalds1da177e2005-04-16 15:20:36 -07003988int
Steve French96daf2b2011-05-27 04:34:02 +00003989CIFSSMBQPathInfo(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003990 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003991 FILE_ALL_INFO *pFindData,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003992 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003993 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003994{
3995/* level 263 SMB_QUERY_FILE_ALL_INFO */
3996 TRANSACTION2_QPI_REQ *pSMB = NULL;
3997 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3998 int rc = 0;
3999 int bytes_returned;
4000 int name_len;
4001 __u16 params, byte_count;
4002
Joe Perchesb6b38f72010-04-21 03:50:45 +00004003/* cFYI(1, "In QPathInfo path %s", searchName); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004004QPathInfoRetry:
4005 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4006 (void **) &pSMBr);
4007 if (rc)
4008 return rc;
4009
4010 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4011 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004012 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4013 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004014 name_len++; /* trailing null */
4015 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004016 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004017 name_len = strnlen(searchName, PATH_MAX);
4018 name_len++; /* trailing null */
4019 strncpy(pSMB->FileName, searchName, name_len);
4020 }
4021
Steve French50c2f752007-07-13 00:33:32 +00004022 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004023 pSMB->TotalDataCount = 0;
4024 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004025 /* BB find exact max SMB PDU from sess structure BB */
4026 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004027 pSMB->MaxSetupCount = 0;
4028 pSMB->Reserved = 0;
4029 pSMB->Flags = 0;
4030 pSMB->Timeout = 0;
4031 pSMB->Reserved2 = 0;
4032 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004033 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004034 pSMB->DataCount = 0;
4035 pSMB->DataOffset = 0;
4036 pSMB->SetupCount = 1;
4037 pSMB->Reserved3 = 0;
4038 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4039 byte_count = params + 1 /* pad */ ;
4040 pSMB->TotalParameterCount = cpu_to_le16(params);
4041 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00004042 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004043 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
4044 else
4045 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004046 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004047 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004048 pSMB->ByteCount = cpu_to_le16(byte_count);
4049
4050 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4051 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4052 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004053 cFYI(1, "Send error in QPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004054 } else { /* decode response */
4055 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4056
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004057 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4058 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004059 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004060 rc = -EIO; /* bad smb */
Jeff Layton820a8032011-05-04 08:05:26 -04004061 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
Steve French50c2f752007-07-13 00:33:32 +00004062 rc = -EIO; /* 24 or 26 expected but we do not read
4063 last field */
4064 else if (pFindData) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004065 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004066 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00004067
4068 /* On legacy responses we do not read the last field,
4069 EAsize, fortunately since it varies by subdialect and
4070 also note it differs on Set vs. Get, ie two bytes or 4
4071 bytes depending but we don't care here */
4072 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004073 size = sizeof(FILE_INFO_STANDARD);
4074 else
4075 size = sizeof(FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004076 memcpy((char *) pFindData,
4077 (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004078 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004079 } else
4080 rc = -ENOMEM;
4081 }
4082 cifs_buf_release(pSMB);
4083 if (rc == -EAGAIN)
4084 goto QPathInfoRetry;
4085
4086 return rc;
4087}
4088
4089int
Steve French96daf2b2011-05-27 04:34:02 +00004090CIFSSMBUnixQFileInfo(const int xid, struct cifs_tcon *tcon,
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004091 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
4092{
4093 struct smb_t2_qfi_req *pSMB = NULL;
4094 struct smb_t2_qfi_rsp *pSMBr = NULL;
4095 int rc = 0;
4096 int bytes_returned;
4097 __u16 params, byte_count;
4098
4099UnixQFileInfoRetry:
4100 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4101 (void **) &pSMBr);
4102 if (rc)
4103 return rc;
4104
4105 params = 2 /* level */ + 2 /* fid */;
4106 pSMB->t2.TotalDataCount = 0;
4107 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4108 /* BB find exact max data count below from sess structure BB */
4109 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4110 pSMB->t2.MaxSetupCount = 0;
4111 pSMB->t2.Reserved = 0;
4112 pSMB->t2.Flags = 0;
4113 pSMB->t2.Timeout = 0;
4114 pSMB->t2.Reserved2 = 0;
4115 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4116 Fid) - 4);
4117 pSMB->t2.DataCount = 0;
4118 pSMB->t2.DataOffset = 0;
4119 pSMB->t2.SetupCount = 1;
4120 pSMB->t2.Reserved3 = 0;
4121 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4122 byte_count = params + 1 /* pad */ ;
4123 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4124 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4125 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4126 pSMB->Pad = 0;
4127 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004128 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004129
4130 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4131 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4132 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00004133 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004134 } else { /* decode response */
4135 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4136
Jeff Layton820a8032011-05-04 08:05:26 -04004137 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004138 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response. "
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004139 "Unix Extensions can be disabled on mount "
Steve Frenchf19159d2010-04-21 04:12:10 +00004140 "by specifying the nosfu mount option.");
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004141 rc = -EIO; /* bad smb */
4142 } else {
4143 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4144 memcpy((char *) pFindData,
4145 (char *) &pSMBr->hdr.Protocol +
4146 data_offset,
4147 sizeof(FILE_UNIX_BASIC_INFO));
4148 }
4149 }
4150
4151 cifs_buf_release(pSMB);
4152 if (rc == -EAGAIN)
4153 goto UnixQFileInfoRetry;
4154
4155 return rc;
4156}
4157
4158int
Steve French96daf2b2011-05-27 04:34:02 +00004159CIFSSMBUnixQPathInfo(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004160 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00004161 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07004162 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004163{
4164/* SMB_QUERY_FILE_UNIX_BASIC */
4165 TRANSACTION2_QPI_REQ *pSMB = NULL;
4166 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4167 int rc = 0;
4168 int bytes_returned = 0;
4169 int name_len;
4170 __u16 params, byte_count;
4171
Joe Perchesb6b38f72010-04-21 03:50:45 +00004172 cFYI(1, "In QPathInfo (Unix) the path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004173UnixQPathInfoRetry:
4174 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4175 (void **) &pSMBr);
4176 if (rc)
4177 return rc;
4178
4179 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4180 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004181 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4182 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004183 name_len++; /* trailing null */
4184 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004185 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004186 name_len = strnlen(searchName, PATH_MAX);
4187 name_len++; /* trailing null */
4188 strncpy(pSMB->FileName, searchName, name_len);
4189 }
4190
Steve French50c2f752007-07-13 00:33:32 +00004191 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004192 pSMB->TotalDataCount = 0;
4193 pSMB->MaxParameterCount = cpu_to_le16(2);
4194 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00004195 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004196 pSMB->MaxSetupCount = 0;
4197 pSMB->Reserved = 0;
4198 pSMB->Flags = 0;
4199 pSMB->Timeout = 0;
4200 pSMB->Reserved2 = 0;
4201 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004202 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004203 pSMB->DataCount = 0;
4204 pSMB->DataOffset = 0;
4205 pSMB->SetupCount = 1;
4206 pSMB->Reserved3 = 0;
4207 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4208 byte_count = params + 1 /* pad */ ;
4209 pSMB->TotalParameterCount = cpu_to_le16(params);
4210 pSMB->ParameterCount = pSMB->TotalParameterCount;
4211 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4212 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004213 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004214 pSMB->ByteCount = cpu_to_le16(byte_count);
4215
4216 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4217 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4218 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004219 cFYI(1, "Send error in QPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004220 } else { /* decode response */
4221 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4222
Jeff Layton820a8032011-05-04 08:05:26 -04004223 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004224 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response. "
Steve French1e71f252007-09-20 15:30:07 +00004225 "Unix Extensions can be disabled on mount "
Joe Perchesb6b38f72010-04-21 03:50:45 +00004226 "by specifying the nosfu mount option.");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004227 rc = -EIO; /* bad smb */
4228 } else {
4229 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4230 memcpy((char *) pFindData,
4231 (char *) &pSMBr->hdr.Protocol +
4232 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00004233 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004234 }
4235 }
4236 cifs_buf_release(pSMB);
4237 if (rc == -EAGAIN)
4238 goto UnixQPathInfoRetry;
4239
4240 return rc;
4241}
4242
Linus Torvalds1da177e2005-04-16 15:20:36 -07004243/* xid, tcon, searchName and codepage are input parms, rest are returned */
4244int
Steve French96daf2b2011-05-27 04:34:02 +00004245CIFSFindFirst(const int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004246 const char *searchName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004247 const struct nls_table *nls_codepage,
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004248 __u16 *pnetfid, __u16 search_flags,
Steve French50c2f752007-07-13 00:33:32 +00004249 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004250{
4251/* level 257 SMB_ */
4252 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
4253 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004254 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004255 int rc = 0;
4256 int bytes_returned = 0;
4257 int name_len;
4258 __u16 params, byte_count;
4259
Joe Perchesb6b38f72010-04-21 03:50:45 +00004260 cFYI(1, "In FindFirst for %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004261
4262findFirstRetry:
4263 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4264 (void **) &pSMBr);
4265 if (rc)
4266 return rc;
4267
4268 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4269 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004270 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4271 PATH_MAX, nls_codepage, remap);
Steve French737b7582005-04-28 22:41:06 -07004272 /* We can not add the asterik earlier in case
4273 it got remapped to 0xF03A as if it were part of the
4274 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004275 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07004276 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07004277 pSMB->FileName[name_len+1] = 0;
4278 pSMB->FileName[name_len+2] = '*';
4279 pSMB->FileName[name_len+3] = 0;
4280 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004281 pSMB->FileName[name_len] = 0; /* null terminate just in case */
4282 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07004283 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004284 } else { /* BB add check for overrun of SMB buf BB */
4285 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004286/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00004287 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004288 free buffer exit; BB */
4289 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07004290 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07004291 pSMB->FileName[name_len+1] = '*';
4292 pSMB->FileName[name_len+2] = 0;
4293 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004294 }
4295
4296 params = 12 + name_len /* includes null */ ;
4297 pSMB->TotalDataCount = 0; /* no EAs */
4298 pSMB->MaxParameterCount = cpu_to_le16(10);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004299 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004300 pSMB->MaxSetupCount = 0;
4301 pSMB->Reserved = 0;
4302 pSMB->Flags = 0;
4303 pSMB->Timeout = 0;
4304 pSMB->Reserved2 = 0;
4305 byte_count = params + 1 /* pad */ ;
4306 pSMB->TotalParameterCount = cpu_to_le16(params);
4307 pSMB->ParameterCount = pSMB->TotalParameterCount;
4308 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00004309 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
4310 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004311 pSMB->DataCount = 0;
4312 pSMB->DataOffset = 0;
4313 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
4314 pSMB->Reserved3 = 0;
4315 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
4316 pSMB->SearchAttributes =
4317 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
4318 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00004319 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004320 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004321 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4322
4323 /* BB what should we set StorageType to? Does it matter? BB */
4324 pSMB->SearchStorageType = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004325 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004326 pSMB->ByteCount = cpu_to_le16(byte_count);
4327
4328 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4329 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07004330 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004331
Steve French88274812006-03-09 22:21:45 +00004332 if (rc) {/* BB add logic to retry regular search if Unix search
4333 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004334 /* BB Add code to handle unsupported level rc */
Joe Perchesb6b38f72010-04-21 03:50:45 +00004335 cFYI(1, "Error in FindFirst = %d", rc);
Steve French1982c342005-08-17 12:38:22 -07004336
Steve French88274812006-03-09 22:21:45 +00004337 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004338
4339 /* BB eventually could optimize out free and realloc of buf */
4340 /* for this case */
4341 if (rc == -EAGAIN)
4342 goto findFirstRetry;
4343 } else { /* decode response */
4344 /* BB remember to free buffer if error BB */
4345 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00004346 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004347 unsigned int lnoff;
4348
Linus Torvalds1da177e2005-04-16 15:20:36 -07004349 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004350 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004351 else
Steve French4b18f2a2008-04-29 00:06:05 +00004352 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004353
4354 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004355 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00004356 psrch_inf->srch_entries_start =
4357 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004358 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004359 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
4360 le16_to_cpu(pSMBr->t2.ParameterOffset));
4361
Steve French790fe572007-07-07 19:25:05 +00004362 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004363 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004364 else
Steve French4b18f2a2008-04-29 00:06:05 +00004365 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004366
Steve French50c2f752007-07-13 00:33:32 +00004367 psrch_inf->entries_in_buffer =
4368 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00004369 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004370 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004371 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004372 if (CIFSMaxBufSize < lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004373 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00004374 psrch_inf->last_entry = NULL;
4375 return rc;
4376 }
4377
Steve French0752f152008-10-07 20:03:33 +00004378 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00004379 lnoff;
4380
Linus Torvalds1da177e2005-04-16 15:20:36 -07004381 *pnetfid = parms->SearchHandle;
4382 } else {
4383 cifs_buf_release(pSMB);
4384 }
4385 }
4386
4387 return rc;
4388}
4389
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004390int CIFSFindNext(const int xid, struct cifs_tcon *tcon, __u16 searchHandle,
4391 __u16 search_flags, struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004392{
4393 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
4394 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004395 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004396 char *response_data;
4397 int rc = 0;
Jeff Layton9438fab2011-08-23 07:21:28 -04004398 int bytes_returned;
4399 unsigned int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004400 __u16 params, byte_count;
4401
Joe Perchesb6b38f72010-04-21 03:50:45 +00004402 cFYI(1, "In FindNext");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004403
Steve French4b18f2a2008-04-29 00:06:05 +00004404 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004405 return -ENOENT;
4406
4407 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4408 (void **) &pSMBr);
4409 if (rc)
4410 return rc;
4411
Steve French50c2f752007-07-13 00:33:32 +00004412 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004413 byte_count = 0;
4414 pSMB->TotalDataCount = 0; /* no EAs */
4415 pSMB->MaxParameterCount = cpu_to_le16(8);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004416 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004417 pSMB->MaxSetupCount = 0;
4418 pSMB->Reserved = 0;
4419 pSMB->Flags = 0;
4420 pSMB->Timeout = 0;
4421 pSMB->Reserved2 = 0;
4422 pSMB->ParameterOffset = cpu_to_le16(
4423 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
4424 pSMB->DataCount = 0;
4425 pSMB->DataOffset = 0;
4426 pSMB->SetupCount = 1;
4427 pSMB->Reserved3 = 0;
4428 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
4429 pSMB->SearchHandle = searchHandle; /* always kept as le */
4430 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00004431 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004432 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4433 pSMB->ResumeKey = psrch_inf->resume_key;
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004434 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004435
4436 name_len = psrch_inf->resume_name_len;
4437 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00004438 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004439 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
4440 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07004441 /* 14 byte parm len above enough for 2 byte null terminator */
4442 pSMB->ResumeFileName[name_len] = 0;
4443 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004444 } else {
4445 rc = -EINVAL;
4446 goto FNext2_err_exit;
4447 }
4448 byte_count = params + 1 /* pad */ ;
4449 pSMB->TotalParameterCount = cpu_to_le16(params);
4450 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004451 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004452 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004453
Linus Torvalds1da177e2005-04-16 15:20:36 -07004454 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4455 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07004456 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004457 if (rc) {
4458 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00004459 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07004460 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00004461 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004462 } else
Joe Perchesb6b38f72010-04-21 03:50:45 +00004463 cFYI(1, "FindNext returned = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004464 } else { /* decode response */
4465 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00004466
Steve French790fe572007-07-07 19:25:05 +00004467 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004468 unsigned int lnoff;
4469
Linus Torvalds1da177e2005-04-16 15:20:36 -07004470 /* BB fixme add lock for file (srch_info) struct here */
4471 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004472 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004473 else
Steve French4b18f2a2008-04-29 00:06:05 +00004474 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004475 response_data = (char *) &pSMBr->hdr.Protocol +
4476 le16_to_cpu(pSMBr->t2.ParameterOffset);
4477 parms = (T2_FNEXT_RSP_PARMS *)response_data;
4478 response_data = (char *)&pSMBr->hdr.Protocol +
4479 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00004480 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00004481 cifs_small_buf_release(
4482 psrch_inf->ntwrk_buf_start);
4483 else
4484 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004485 psrch_inf->srch_entries_start = response_data;
4486 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004487 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00004488 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004489 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004490 else
Steve French4b18f2a2008-04-29 00:06:05 +00004491 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00004492 psrch_inf->entries_in_buffer =
4493 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004494 psrch_inf->index_of_last_entry +=
4495 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004496 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004497 if (CIFSMaxBufSize < lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004498 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00004499 psrch_inf->last_entry = NULL;
4500 return rc;
4501 } else
4502 psrch_inf->last_entry =
4503 psrch_inf->srch_entries_start + lnoff;
4504
Joe Perchesb6b38f72010-04-21 03:50:45 +00004505/* cFYI(1, "fnxt2 entries in buf %d index_of_last %d",
4506 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004507
4508 /* BB fixme add unlock here */
4509 }
4510
4511 }
4512
4513 /* BB On error, should we leave previous search buf (and count and
4514 last entry fields) intact or free the previous one? */
4515
4516 /* Note: On -EAGAIN error only caller can retry on handle based calls
4517 since file handle passed in no longer valid */
4518FNext2_err_exit:
4519 if (rc != 0)
4520 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004521 return rc;
4522}
4523
4524int
Steve French96daf2b2011-05-27 04:34:02 +00004525CIFSFindClose(const int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004526 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004527{
4528 int rc = 0;
4529 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004530
Joe Perchesb6b38f72010-04-21 03:50:45 +00004531 cFYI(1, "In CIFSSMBFindClose");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004532 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
4533
4534 /* no sense returning error if session restarted
4535 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00004536 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004537 return 0;
4538 if (rc)
4539 return rc;
4540
Linus Torvalds1da177e2005-04-16 15:20:36 -07004541 pSMB->FileID = searchHandle;
4542 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04004543 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004544 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00004545 cERROR(1, "Send error in FindClose = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00004546
Steve Frencha4544342005-08-24 13:59:35 -07004547 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004548
4549 /* Since session is dead, search handle closed on server already */
4550 if (rc == -EAGAIN)
4551 rc = 0;
4552
4553 return rc;
4554}
4555
Linus Torvalds1da177e2005-04-16 15:20:36 -07004556int
Steve French96daf2b2011-05-27 04:34:02 +00004557CIFSGetSrvInodeNumber(const int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004558 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00004559 __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00004560 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004561{
4562 int rc = 0;
4563 TRANSACTION2_QPI_REQ *pSMB = NULL;
4564 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4565 int name_len, bytes_returned;
4566 __u16 params, byte_count;
4567
Joe Perchesb6b38f72010-04-21 03:50:45 +00004568 cFYI(1, "In GetSrvInodeNum for %s", searchName);
Steve French790fe572007-07-07 19:25:05 +00004569 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00004570 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004571
4572GetInodeNumberRetry:
4573 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004574 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004575 if (rc)
4576 return rc;
4577
Linus Torvalds1da177e2005-04-16 15:20:36 -07004578 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4579 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004580 cifsConvertToUTF16((__le16 *) pSMB->FileName,
4581 searchName, PATH_MAX, nls_codepage,
4582 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004583 name_len++; /* trailing null */
4584 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004585 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004586 name_len = strnlen(searchName, PATH_MAX);
4587 name_len++; /* trailing null */
4588 strncpy(pSMB->FileName, searchName, name_len);
4589 }
4590
4591 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4592 pSMB->TotalDataCount = 0;
4593 pSMB->MaxParameterCount = cpu_to_le16(2);
4594 /* BB find exact max data count below from sess structure BB */
4595 pSMB->MaxDataCount = cpu_to_le16(4000);
4596 pSMB->MaxSetupCount = 0;
4597 pSMB->Reserved = 0;
4598 pSMB->Flags = 0;
4599 pSMB->Timeout = 0;
4600 pSMB->Reserved2 = 0;
4601 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004602 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004603 pSMB->DataCount = 0;
4604 pSMB->DataOffset = 0;
4605 pSMB->SetupCount = 1;
4606 pSMB->Reserved3 = 0;
4607 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4608 byte_count = params + 1 /* pad */ ;
4609 pSMB->TotalParameterCount = cpu_to_le16(params);
4610 pSMB->ParameterCount = pSMB->TotalParameterCount;
4611 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4612 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004613 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004614 pSMB->ByteCount = cpu_to_le16(byte_count);
4615
4616 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4617 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4618 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004619 cFYI(1, "error %d in QueryInternalInfo", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004620 } else {
4621 /* decode response */
4622 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004623 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04004624 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004625 /* If rc should we check for EOPNOSUPP and
4626 disable the srvino flag? or in caller? */
4627 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00004628 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004629 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4630 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00004631 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004632 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00004633 if (count < 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004634 cFYI(1, "Illegal size ret in QryIntrnlInf");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004635 rc = -EIO;
4636 goto GetInodeNumOut;
4637 }
4638 pfinfo = (struct file_internal_info *)
4639 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00004640 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004641 }
4642 }
4643GetInodeNumOut:
4644 cifs_buf_release(pSMB);
4645 if (rc == -EAGAIN)
4646 goto GetInodeNumberRetry;
4647 return rc;
4648}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004649
Igor Mammedovfec45852008-05-16 13:06:30 +04004650/* parses DFS refferal V3 structure
4651 * caller is responsible for freeing target_nodes
4652 * returns:
4653 * on success - 0
4654 * on failure - errno
4655 */
4656static int
Steve Frencha1fe78f2008-05-16 18:48:38 +00004657parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
Igor Mammedovfec45852008-05-16 13:06:30 +04004658 unsigned int *num_of_nodes,
4659 struct dfs_info3_param **target_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004660 const struct nls_table *nls_codepage, int remap,
4661 const char *searchName)
Igor Mammedovfec45852008-05-16 13:06:30 +04004662{
4663 int i, rc = 0;
4664 char *data_end;
4665 bool is_unicode;
4666 struct dfs_referral_level_3 *ref;
4667
Harvey Harrison5ca33c62008-07-23 17:45:58 -07004668 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4669 is_unicode = true;
4670 else
4671 is_unicode = false;
Igor Mammedovfec45852008-05-16 13:06:30 +04004672 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
4673
4674 if (*num_of_nodes < 1) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004675 cERROR(1, "num_referrals: must be at least > 0,"
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004676 "but we get num_referrals = %d", *num_of_nodes);
Igor Mammedovfec45852008-05-16 13:06:30 +04004677 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004678 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004679 }
4680
4681 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
Al Viro1d92cfd2008-06-02 10:59:02 +01004682 if (ref->VersionNumber != cpu_to_le16(3)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004683 cERROR(1, "Referrals of V%d version are not supported,"
4684 "should be V3", le16_to_cpu(ref->VersionNumber));
Igor Mammedovfec45852008-05-16 13:06:30 +04004685 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004686 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004687 }
4688
4689 /* get the upper boundary of the resp buffer */
4690 data_end = (char *)(&(pSMBr->PathConsumed)) +
4691 le16_to_cpu(pSMBr->t2.DataCount);
4692
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004693 cFYI(1, "num_referrals: %d dfs flags: 0x%x ...",
Igor Mammedovfec45852008-05-16 13:06:30 +04004694 *num_of_nodes,
Joe Perchesb6b38f72010-04-21 03:50:45 +00004695 le32_to_cpu(pSMBr->DFSFlags));
Igor Mammedovfec45852008-05-16 13:06:30 +04004696
4697 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
4698 *num_of_nodes, GFP_KERNEL);
4699 if (*target_nodes == NULL) {
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004700 cERROR(1, "Failed to allocate buffer for target_nodes");
Igor Mammedovfec45852008-05-16 13:06:30 +04004701 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004702 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004703 }
4704
Daniel Mack3ad2f3f2010-02-03 08:01:28 +08004705 /* collect necessary data from referrals */
Igor Mammedovfec45852008-05-16 13:06:30 +04004706 for (i = 0; i < *num_of_nodes; i++) {
4707 char *temp;
4708 int max_len;
4709 struct dfs_info3_param *node = (*target_nodes)+i;
4710
Steve French0e0d2cf2009-05-01 05:27:32 +00004711 node->flags = le32_to_cpu(pSMBr->DFSFlags);
Igor Mammedov2c556082008-10-23 13:58:42 +04004712 if (is_unicode) {
Jeff Layton331c3132008-12-17 06:31:53 -05004713 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4714 GFP_KERNEL);
Steve French2920ee22009-08-31 15:27:26 +00004715 if (tmp == NULL) {
4716 rc = -ENOMEM;
4717 goto parse_DFS_referrals_exit;
4718 }
Steve Frenchacbbb762012-01-18 22:32:33 -06004719 cifsConvertToUTF16((__le16 *) tmp, searchName,
4720 PATH_MAX, nls_codepage, remap);
4721 node->path_consumed = cifs_utf16_bytes(tmp,
Jeff Layton69f801f2009-04-30 06:46:32 -04004722 le16_to_cpu(pSMBr->PathConsumed),
Igor Mammedov2c556082008-10-23 13:58:42 +04004723 nls_codepage);
4724 kfree(tmp);
4725 } else
4726 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4727
Igor Mammedovfec45852008-05-16 13:06:30 +04004728 node->server_type = le16_to_cpu(ref->ServerType);
4729 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4730
4731 /* copy DfsPath */
4732 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4733 max_len = data_end - temp;
Steve Frenchacbbb762012-01-18 22:32:33 -06004734 node->path_name = cifs_strndup_from_utf16(temp, max_len,
4735 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004736 if (!node->path_name) {
4737 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004738 goto parse_DFS_referrals_exit;
Jeff Layton066ce682009-04-30 07:16:14 -04004739 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004740
4741 /* copy link target UNC */
4742 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4743 max_len = data_end - temp;
Steve Frenchacbbb762012-01-18 22:32:33 -06004744 node->node_name = cifs_strndup_from_utf16(temp, max_len,
4745 is_unicode, nls_codepage);
Stefan Metzmacherd8f27992012-05-04 00:19:28 +02004746 if (!node->node_name) {
Jeff Laytond8e2f532009-05-14 07:46:59 -04004747 rc = -ENOMEM;
Stefan Metzmacherd8f27992012-05-04 00:19:28 +02004748 goto parse_DFS_referrals_exit;
4749 }
4750
4751 ref++;
Igor Mammedovfec45852008-05-16 13:06:30 +04004752 }
4753
Steve Frencha1fe78f2008-05-16 18:48:38 +00004754parse_DFS_referrals_exit:
Igor Mammedovfec45852008-05-16 13:06:30 +04004755 if (rc) {
4756 free_dfs_info_array(*target_nodes, *num_of_nodes);
4757 *target_nodes = NULL;
4758 *num_of_nodes = 0;
4759 }
4760 return rc;
4761}
4762
Linus Torvalds1da177e2005-04-16 15:20:36 -07004763int
Steve French96daf2b2011-05-27 04:34:02 +00004764CIFSGetDFSRefer(const int xid, struct cifs_ses *ses,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004765 const unsigned char *searchName,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004766 struct dfs_info3_param **target_nodes,
4767 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004768 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004769{
4770/* TRANS2_GET_DFS_REFERRAL */
4771 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4772 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004773 int rc = 0;
4774 int bytes_returned;
4775 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004776 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004777 *num_of_nodes = 0;
4778 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004779
Joe Perchesb6b38f72010-04-21 03:50:45 +00004780 cFYI(1, "In GetDFSRefer the path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004781 if (ses == NULL)
4782 return -ENODEV;
4783getDFSRetry:
4784 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4785 (void **) &pSMBr);
4786 if (rc)
4787 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004788
4789 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004790 but should never be null here anyway */
Pavel Shilovsky88257362012-05-23 14:01:59 +04004791 pSMB->hdr.Mid = get_next_mid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004792 pSMB->hdr.Tid = ses->ipc_tid;
4793 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004794 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004795 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004796 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004797 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004798
4799 if (ses->capabilities & CAP_UNICODE) {
4800 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4801 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004802 cifsConvertToUTF16((__le16 *) pSMB->RequestFileName,
4803 searchName, PATH_MAX, nls_codepage,
4804 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004805 name_len++; /* trailing null */
4806 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004807 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004808 name_len = strnlen(searchName, PATH_MAX);
4809 name_len++; /* trailing null */
4810 strncpy(pSMB->RequestFileName, searchName, name_len);
4811 }
4812
Steve French790fe572007-07-07 19:25:05 +00004813 if (ses->server) {
Steve French96daf2b2011-05-27 04:34:02 +00004814 if (ses->server->sec_mode &
Steve French1a4e15a2006-10-12 21:33:51 +00004815 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4816 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4817 }
4818
Steve French50c2f752007-07-13 00:33:32 +00004819 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004820
Linus Torvalds1da177e2005-04-16 15:20:36 -07004821 params = 2 /* level */ + name_len /*includes null */ ;
4822 pSMB->TotalDataCount = 0;
4823 pSMB->DataCount = 0;
4824 pSMB->DataOffset = 0;
4825 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004826 /* BB find exact max SMB PDU from sess structure BB */
4827 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004828 pSMB->MaxSetupCount = 0;
4829 pSMB->Reserved = 0;
4830 pSMB->Flags = 0;
4831 pSMB->Timeout = 0;
4832 pSMB->Reserved2 = 0;
4833 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004834 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004835 pSMB->SetupCount = 1;
4836 pSMB->Reserved3 = 0;
4837 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4838 byte_count = params + 3 /* pad */ ;
4839 pSMB->ParameterCount = cpu_to_le16(params);
4840 pSMB->TotalParameterCount = pSMB->ParameterCount;
4841 pSMB->MaxReferralLevel = cpu_to_le16(3);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004842 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004843 pSMB->ByteCount = cpu_to_le16(byte_count);
4844
4845 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4846 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4847 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004848 cFYI(1, "Send error in GetDFSRefer = %d", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004849 goto GetDFSRefExit;
4850 }
4851 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004852
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004853 /* BB Also check if enough total bytes returned? */
Jeff Layton820a8032011-05-04 08:05:26 -04004854 if (rc || get_bcc(&pSMBr->hdr) < 17) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004855 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004856 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004857 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004858
Joe Perchesb6b38f72010-04-21 03:50:45 +00004859 cFYI(1, "Decoding GetDFSRefer response BCC: %d Offset %d",
Jeff Layton820a8032011-05-04 08:05:26 -04004860 get_bcc(&pSMBr->hdr),
Joe Perchesb6b38f72010-04-21 03:50:45 +00004861 le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04004862
4863 /* parse returned result into more usable form */
Steve Frencha1fe78f2008-05-16 18:48:38 +00004864 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004865 target_nodes, nls_codepage, remap,
4866 searchName);
Igor Mammedovfec45852008-05-16 13:06:30 +04004867
Linus Torvalds1da177e2005-04-16 15:20:36 -07004868GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004869 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004870
4871 if (rc == -EAGAIN)
4872 goto getDFSRetry;
4873
4874 return rc;
4875}
4876
Steve French20962432005-09-21 22:05:57 -07004877/* Query File System Info such as free space to old servers such as Win 9x */
4878int
Steve French96daf2b2011-05-27 04:34:02 +00004879SMBOldQFSInfo(const int xid, struct cifs_tcon *tcon, struct kstatfs *FSData)
Steve French20962432005-09-21 22:05:57 -07004880{
4881/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4882 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4883 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4884 FILE_SYSTEM_ALLOC_INFO *response_data;
4885 int rc = 0;
4886 int bytes_returned = 0;
4887 __u16 params, byte_count;
4888
Joe Perchesb6b38f72010-04-21 03:50:45 +00004889 cFYI(1, "OldQFSInfo");
Steve French20962432005-09-21 22:05:57 -07004890oldQFSInfoRetry:
4891 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4892 (void **) &pSMBr);
4893 if (rc)
4894 return rc;
Steve French20962432005-09-21 22:05:57 -07004895
4896 params = 2; /* level */
4897 pSMB->TotalDataCount = 0;
4898 pSMB->MaxParameterCount = cpu_to_le16(2);
4899 pSMB->MaxDataCount = cpu_to_le16(1000);
4900 pSMB->MaxSetupCount = 0;
4901 pSMB->Reserved = 0;
4902 pSMB->Flags = 0;
4903 pSMB->Timeout = 0;
4904 pSMB->Reserved2 = 0;
4905 byte_count = params + 1 /* pad */ ;
4906 pSMB->TotalParameterCount = cpu_to_le16(params);
4907 pSMB->ParameterCount = pSMB->TotalParameterCount;
4908 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4909 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4910 pSMB->DataCount = 0;
4911 pSMB->DataOffset = 0;
4912 pSMB->SetupCount = 1;
4913 pSMB->Reserved3 = 0;
4914 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4915 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004916 inc_rfc1001_len(pSMB, byte_count);
Steve French20962432005-09-21 22:05:57 -07004917 pSMB->ByteCount = cpu_to_le16(byte_count);
4918
4919 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4920 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4921 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004922 cFYI(1, "Send error in QFSInfo = %d", rc);
Steve French20962432005-09-21 22:05:57 -07004923 } else { /* decode response */
4924 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4925
Jeff Layton820a8032011-05-04 08:05:26 -04004926 if (rc || get_bcc(&pSMBr->hdr) < 18)
Steve French20962432005-09-21 22:05:57 -07004927 rc = -EIO; /* bad smb */
4928 else {
4929 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004930 cFYI(1, "qfsinf resp BCC: %d Offset %d",
Jeff Layton820a8032011-05-04 08:05:26 -04004931 get_bcc(&pSMBr->hdr), data_offset);
Steve French20962432005-09-21 22:05:57 -07004932
Steve French50c2f752007-07-13 00:33:32 +00004933 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004934 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4935 FSData->f_bsize =
4936 le16_to_cpu(response_data->BytesPerSector) *
4937 le32_to_cpu(response_data->
4938 SectorsPerAllocationUnit);
4939 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004940 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004941 FSData->f_bfree = FSData->f_bavail =
4942 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004943 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
4944 (unsigned long long)FSData->f_blocks,
4945 (unsigned long long)FSData->f_bfree,
4946 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07004947 }
4948 }
4949 cifs_buf_release(pSMB);
4950
4951 if (rc == -EAGAIN)
4952 goto oldQFSInfoRetry;
4953
4954 return rc;
4955}
4956
Linus Torvalds1da177e2005-04-16 15:20:36 -07004957int
Steve French96daf2b2011-05-27 04:34:02 +00004958CIFSSMBQFSInfo(const int xid, struct cifs_tcon *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004959{
4960/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4961 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4962 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4963 FILE_SYSTEM_INFO *response_data;
4964 int rc = 0;
4965 int bytes_returned = 0;
4966 __u16 params, byte_count;
4967
Joe Perchesb6b38f72010-04-21 03:50:45 +00004968 cFYI(1, "In QFSInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004969QFSInfoRetry:
4970 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4971 (void **) &pSMBr);
4972 if (rc)
4973 return rc;
4974
4975 params = 2; /* level */
4976 pSMB->TotalDataCount = 0;
4977 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004978 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004979 pSMB->MaxSetupCount = 0;
4980 pSMB->Reserved = 0;
4981 pSMB->Flags = 0;
4982 pSMB->Timeout = 0;
4983 pSMB->Reserved2 = 0;
4984 byte_count = params + 1 /* pad */ ;
4985 pSMB->TotalParameterCount = cpu_to_le16(params);
4986 pSMB->ParameterCount = pSMB->TotalParameterCount;
4987 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004988 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004989 pSMB->DataCount = 0;
4990 pSMB->DataOffset = 0;
4991 pSMB->SetupCount = 1;
4992 pSMB->Reserved3 = 0;
4993 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4994 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004995 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004996 pSMB->ByteCount = cpu_to_le16(byte_count);
4997
4998 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4999 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5000 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005001 cFYI(1, "Send error in QFSInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005002 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00005003 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005004
Jeff Layton820a8032011-05-04 08:05:26 -04005005 if (rc || get_bcc(&pSMBr->hdr) < 24)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005006 rc = -EIO; /* bad smb */
5007 else {
5008 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005009
5010 response_data =
5011 (FILE_SYSTEM_INFO
5012 *) (((char *) &pSMBr->hdr.Protocol) +
5013 data_offset);
5014 FSData->f_bsize =
5015 le32_to_cpu(response_data->BytesPerSector) *
5016 le32_to_cpu(response_data->
5017 SectorsPerAllocationUnit);
5018 FSData->f_blocks =
5019 le64_to_cpu(response_data->TotalAllocationUnits);
5020 FSData->f_bfree = FSData->f_bavail =
5021 le64_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesb6b38f72010-04-21 03:50:45 +00005022 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
5023 (unsigned long long)FSData->f_blocks,
5024 (unsigned long long)FSData->f_bfree,
5025 FSData->f_bsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005026 }
5027 }
5028 cifs_buf_release(pSMB);
5029
5030 if (rc == -EAGAIN)
5031 goto QFSInfoRetry;
5032
5033 return rc;
5034}
5035
5036int
Steve French96daf2b2011-05-27 04:34:02 +00005037CIFSSMBQFSAttributeInfo(const int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005038{
5039/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
5040 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5041 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5042 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
5043 int rc = 0;
5044 int bytes_returned = 0;
5045 __u16 params, byte_count;
5046
Joe Perchesb6b38f72010-04-21 03:50:45 +00005047 cFYI(1, "In QFSAttributeInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005048QFSAttributeRetry:
5049 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5050 (void **) &pSMBr);
5051 if (rc)
5052 return rc;
5053
5054 params = 2; /* level */
5055 pSMB->TotalDataCount = 0;
5056 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005057 /* BB find exact max SMB PDU from sess structure BB */
5058 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005059 pSMB->MaxSetupCount = 0;
5060 pSMB->Reserved = 0;
5061 pSMB->Flags = 0;
5062 pSMB->Timeout = 0;
5063 pSMB->Reserved2 = 0;
5064 byte_count = params + 1 /* pad */ ;
5065 pSMB->TotalParameterCount = cpu_to_le16(params);
5066 pSMB->ParameterCount = pSMB->TotalParameterCount;
5067 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005068 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005069 pSMB->DataCount = 0;
5070 pSMB->DataOffset = 0;
5071 pSMB->SetupCount = 1;
5072 pSMB->Reserved3 = 0;
5073 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5074 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005075 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005076 pSMB->ByteCount = cpu_to_le16(byte_count);
5077
5078 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5079 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5080 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005081 cERROR(1, "Send error in QFSAttributeInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005082 } else { /* decode response */
5083 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5084
Jeff Layton820a8032011-05-04 08:05:26 -04005085 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Steve French50c2f752007-07-13 00:33:32 +00005086 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005087 rc = -EIO; /* bad smb */
5088 } else {
5089 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5090 response_data =
5091 (FILE_SYSTEM_ATTRIBUTE_INFO
5092 *) (((char *) &pSMBr->hdr.Protocol) +
5093 data_offset);
5094 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005095 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005096 }
5097 }
5098 cifs_buf_release(pSMB);
5099
5100 if (rc == -EAGAIN)
5101 goto QFSAttributeRetry;
5102
5103 return rc;
5104}
5105
5106int
Steve French96daf2b2011-05-27 04:34:02 +00005107CIFSSMBQFSDeviceInfo(const int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005108{
5109/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
5110 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5111 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5112 FILE_SYSTEM_DEVICE_INFO *response_data;
5113 int rc = 0;
5114 int bytes_returned = 0;
5115 __u16 params, byte_count;
5116
Joe Perchesb6b38f72010-04-21 03:50:45 +00005117 cFYI(1, "In QFSDeviceInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005118QFSDeviceRetry:
5119 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5120 (void **) &pSMBr);
5121 if (rc)
5122 return rc;
5123
5124 params = 2; /* level */
5125 pSMB->TotalDataCount = 0;
5126 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005127 /* BB find exact max SMB PDU from sess structure BB */
5128 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005129 pSMB->MaxSetupCount = 0;
5130 pSMB->Reserved = 0;
5131 pSMB->Flags = 0;
5132 pSMB->Timeout = 0;
5133 pSMB->Reserved2 = 0;
5134 byte_count = params + 1 /* pad */ ;
5135 pSMB->TotalParameterCount = cpu_to_le16(params);
5136 pSMB->ParameterCount = pSMB->TotalParameterCount;
5137 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005138 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005139
5140 pSMB->DataCount = 0;
5141 pSMB->DataOffset = 0;
5142 pSMB->SetupCount = 1;
5143 pSMB->Reserved3 = 0;
5144 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5145 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005146 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005147 pSMB->ByteCount = cpu_to_le16(byte_count);
5148
5149 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5150 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5151 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005152 cFYI(1, "Send error in QFSDeviceInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005153 } else { /* decode response */
5154 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5155
Jeff Layton820a8032011-05-04 08:05:26 -04005156 if (rc || get_bcc(&pSMBr->hdr) <
5157 sizeof(FILE_SYSTEM_DEVICE_INFO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005158 rc = -EIO; /* bad smb */
5159 else {
5160 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5161 response_data =
Steve French737b7582005-04-28 22:41:06 -07005162 (FILE_SYSTEM_DEVICE_INFO *)
5163 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07005164 data_offset);
5165 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005166 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005167 }
5168 }
5169 cifs_buf_release(pSMB);
5170
5171 if (rc == -EAGAIN)
5172 goto QFSDeviceRetry;
5173
5174 return rc;
5175}
5176
5177int
Steve French96daf2b2011-05-27 04:34:02 +00005178CIFSSMBQFSUnixInfo(const int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005179{
5180/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
5181 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5182 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5183 FILE_SYSTEM_UNIX_INFO *response_data;
5184 int rc = 0;
5185 int bytes_returned = 0;
5186 __u16 params, byte_count;
5187
Joe Perchesb6b38f72010-04-21 03:50:45 +00005188 cFYI(1, "In QFSUnixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005189QFSUnixRetry:
Jeff Laytonf5695992010-09-29 15:27:08 -04005190 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5191 (void **) &pSMB, (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005192 if (rc)
5193 return rc;
5194
5195 params = 2; /* level */
5196 pSMB->TotalDataCount = 0;
5197 pSMB->DataCount = 0;
5198 pSMB->DataOffset = 0;
5199 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005200 /* BB find exact max SMB PDU from sess structure BB */
5201 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005202 pSMB->MaxSetupCount = 0;
5203 pSMB->Reserved = 0;
5204 pSMB->Flags = 0;
5205 pSMB->Timeout = 0;
5206 pSMB->Reserved2 = 0;
5207 byte_count = params + 1 /* pad */ ;
5208 pSMB->ParameterCount = cpu_to_le16(params);
5209 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005210 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5211 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005212 pSMB->SetupCount = 1;
5213 pSMB->Reserved3 = 0;
5214 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5215 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005216 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005217 pSMB->ByteCount = cpu_to_le16(byte_count);
5218
5219 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5220 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5221 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005222 cERROR(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005223 } else { /* decode response */
5224 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5225
Jeff Layton820a8032011-05-04 08:05:26 -04005226 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005227 rc = -EIO; /* bad smb */
5228 } else {
5229 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5230 response_data =
5231 (FILE_SYSTEM_UNIX_INFO
5232 *) (((char *) &pSMBr->hdr.Protocol) +
5233 data_offset);
5234 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005235 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005236 }
5237 }
5238 cifs_buf_release(pSMB);
5239
5240 if (rc == -EAGAIN)
5241 goto QFSUnixRetry;
5242
5243
5244 return rc;
5245}
5246
Jeremy Allisonac670552005-06-22 17:26:35 -07005247int
Steve French96daf2b2011-05-27 04:34:02 +00005248CIFSSMBSetFSUnixInfo(const int xid, struct cifs_tcon *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07005249{
5250/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
5251 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
5252 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
5253 int rc = 0;
5254 int bytes_returned = 0;
5255 __u16 params, param_offset, offset, byte_count;
5256
Joe Perchesb6b38f72010-04-21 03:50:45 +00005257 cFYI(1, "In SETFSUnixInfo");
Jeremy Allisonac670552005-06-22 17:26:35 -07005258SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00005259 /* BB switch to small buf init to save memory */
Jeff Laytonf5695992010-09-29 15:27:08 -04005260 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5261 (void **) &pSMB, (void **) &pSMBr);
Jeremy Allisonac670552005-06-22 17:26:35 -07005262 if (rc)
5263 return rc;
5264
5265 params = 4; /* 2 bytes zero followed by info level. */
5266 pSMB->MaxSetupCount = 0;
5267 pSMB->Reserved = 0;
5268 pSMB->Flags = 0;
5269 pSMB->Timeout = 0;
5270 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00005271 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
5272 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07005273 offset = param_offset + params;
5274
5275 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00005276 /* BB find exact max SMB PDU from sess structure BB */
5277 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07005278 pSMB->SetupCount = 1;
5279 pSMB->Reserved3 = 0;
5280 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
5281 byte_count = 1 /* pad */ + params + 12;
5282
5283 pSMB->DataCount = cpu_to_le16(12);
5284 pSMB->ParameterCount = cpu_to_le16(params);
5285 pSMB->TotalDataCount = pSMB->DataCount;
5286 pSMB->TotalParameterCount = pSMB->ParameterCount;
5287 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5288 pSMB->DataOffset = cpu_to_le16(offset);
5289
5290 /* Params. */
5291 pSMB->FileNum = 0;
5292 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
5293
5294 /* Data. */
5295 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
5296 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
5297 pSMB->ClientUnixCap = cpu_to_le64(cap);
5298
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005299 inc_rfc1001_len(pSMB, byte_count);
Jeremy Allisonac670552005-06-22 17:26:35 -07005300 pSMB->ByteCount = cpu_to_le16(byte_count);
5301
5302 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5303 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5304 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005305 cERROR(1, "Send error in SETFSUnixInfo = %d", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07005306 } else { /* decode response */
5307 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00005308 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07005309 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07005310 }
5311 cifs_buf_release(pSMB);
5312
5313 if (rc == -EAGAIN)
5314 goto SETFSUnixRetry;
5315
5316 return rc;
5317}
5318
5319
Linus Torvalds1da177e2005-04-16 15:20:36 -07005320
5321int
Steve French96daf2b2011-05-27 04:34:02 +00005322CIFSSMBQFSPosixInfo(const int xid, struct cifs_tcon *tcon,
Steve French737b7582005-04-28 22:41:06 -07005323 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005324{
5325/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
5326 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5327 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5328 FILE_SYSTEM_POSIX_INFO *response_data;
5329 int rc = 0;
5330 int bytes_returned = 0;
5331 __u16 params, byte_count;
5332
Joe Perchesb6b38f72010-04-21 03:50:45 +00005333 cFYI(1, "In QFSPosixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005334QFSPosixRetry:
5335 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5336 (void **) &pSMBr);
5337 if (rc)
5338 return rc;
5339
5340 params = 2; /* level */
5341 pSMB->TotalDataCount = 0;
5342 pSMB->DataCount = 0;
5343 pSMB->DataOffset = 0;
5344 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005345 /* BB find exact max SMB PDU from sess structure BB */
5346 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005347 pSMB->MaxSetupCount = 0;
5348 pSMB->Reserved = 0;
5349 pSMB->Flags = 0;
5350 pSMB->Timeout = 0;
5351 pSMB->Reserved2 = 0;
5352 byte_count = params + 1 /* pad */ ;
5353 pSMB->ParameterCount = cpu_to_le16(params);
5354 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005355 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5356 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005357 pSMB->SetupCount = 1;
5358 pSMB->Reserved3 = 0;
5359 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5360 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005361 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005362 pSMB->ByteCount = cpu_to_le16(byte_count);
5363
5364 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5365 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5366 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005367 cFYI(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005368 } else { /* decode response */
5369 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5370
Jeff Layton820a8032011-05-04 08:05:26 -04005371 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005372 rc = -EIO; /* bad smb */
5373 } else {
5374 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5375 response_data =
5376 (FILE_SYSTEM_POSIX_INFO
5377 *) (((char *) &pSMBr->hdr.Protocol) +
5378 data_offset);
5379 FSData->f_bsize =
5380 le32_to_cpu(response_data->BlockSize);
5381 FSData->f_blocks =
5382 le64_to_cpu(response_data->TotalBlocks);
5383 FSData->f_bfree =
5384 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00005385 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005386 FSData->f_bavail = FSData->f_bfree;
5387 } else {
5388 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00005389 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005390 }
Steve French790fe572007-07-07 19:25:05 +00005391 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005392 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00005393 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00005394 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005395 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00005396 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005397 }
5398 }
5399 cifs_buf_release(pSMB);
5400
5401 if (rc == -EAGAIN)
5402 goto QFSPosixRetry;
5403
5404 return rc;
5405}
5406
5407
Steve French50c2f752007-07-13 00:33:32 +00005408/* We can not use write of zero bytes trick to
5409 set file size due to need for large file support. Also note that
5410 this SetPathInfo is preferred to SetFileInfo based method in next
Linus Torvalds1da177e2005-04-16 15:20:36 -07005411 routine which is only needed to work around a sharing violation bug
5412 in Samba which this routine can run into */
5413
5414int
Steve French96daf2b2011-05-27 04:34:02 +00005415CIFSSMBSetEOF(const int xid, struct cifs_tcon *tcon, const char *fileName,
Steve French4b18f2a2008-04-29 00:06:05 +00005416 __u64 size, bool SetAllocation,
Steve French737b7582005-04-28 22:41:06 -07005417 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005418{
5419 struct smb_com_transaction2_spi_req *pSMB = NULL;
5420 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5421 struct file_end_of_file_info *parm_data;
5422 int name_len;
5423 int rc = 0;
5424 int bytes_returned = 0;
5425 __u16 params, byte_count, data_count, param_offset, offset;
5426
Joe Perchesb6b38f72010-04-21 03:50:45 +00005427 cFYI(1, "In SetEOF");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005428SetEOFRetry:
5429 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5430 (void **) &pSMBr);
5431 if (rc)
5432 return rc;
5433
5434 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5435 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005436 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5437 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005438 name_len++; /* trailing null */
5439 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005440 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005441 name_len = strnlen(fileName, PATH_MAX);
5442 name_len++; /* trailing null */
5443 strncpy(pSMB->FileName, fileName, name_len);
5444 }
5445 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005446 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005447 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07005448 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005449 pSMB->MaxSetupCount = 0;
5450 pSMB->Reserved = 0;
5451 pSMB->Flags = 0;
5452 pSMB->Timeout = 0;
5453 pSMB->Reserved2 = 0;
5454 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005455 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005456 offset = param_offset + params;
Steve French790fe572007-07-07 19:25:05 +00005457 if (SetAllocation) {
Steve French50c2f752007-07-13 00:33:32 +00005458 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5459 pSMB->InformationLevel =
5460 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5461 else
5462 pSMB->InformationLevel =
5463 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5464 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005465 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5466 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005467 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005468 else
5469 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005470 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005471 }
5472
5473 parm_data =
5474 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
5475 offset);
5476 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5477 pSMB->DataOffset = cpu_to_le16(offset);
5478 pSMB->SetupCount = 1;
5479 pSMB->Reserved3 = 0;
5480 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5481 byte_count = 3 /* pad */ + params + data_count;
5482 pSMB->DataCount = cpu_to_le16(data_count);
5483 pSMB->TotalDataCount = pSMB->DataCount;
5484 pSMB->ParameterCount = cpu_to_le16(params);
5485 pSMB->TotalParameterCount = pSMB->ParameterCount;
5486 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005487 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005488 parm_data->FileSize = cpu_to_le64(size);
5489 pSMB->ByteCount = cpu_to_le16(byte_count);
5490 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5491 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005492 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005493 cFYI(1, "SetPathInfo (file size) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005494
5495 cifs_buf_release(pSMB);
5496
5497 if (rc == -EAGAIN)
5498 goto SetEOFRetry;
5499
5500 return rc;
5501}
5502
5503int
Steve French96daf2b2011-05-27 04:34:02 +00005504CIFSSMBSetFileSize(const int xid, struct cifs_tcon *tcon, __u64 size,
Steve French4b18f2a2008-04-29 00:06:05 +00005505 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005506{
5507 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005508 struct file_end_of_file_info *parm_data;
5509 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005510 __u16 params, param_offset, offset, byte_count, count;
5511
Joe Perchesb6b38f72010-04-21 03:50:45 +00005512 cFYI(1, "SetFileSize (via SetFileInfo) %lld",
5513 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07005514 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5515
Linus Torvalds1da177e2005-04-16 15:20:36 -07005516 if (rc)
5517 return rc;
5518
5519 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5520 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005521
Linus Torvalds1da177e2005-04-16 15:20:36 -07005522 params = 6;
5523 pSMB->MaxSetupCount = 0;
5524 pSMB->Reserved = 0;
5525 pSMB->Flags = 0;
5526 pSMB->Timeout = 0;
5527 pSMB->Reserved2 = 0;
5528 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5529 offset = param_offset + params;
5530
Linus Torvalds1da177e2005-04-16 15:20:36 -07005531 count = sizeof(struct file_end_of_file_info);
5532 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005533 /* BB find exact max SMB PDU from sess structure BB */
5534 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005535 pSMB->SetupCount = 1;
5536 pSMB->Reserved3 = 0;
5537 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5538 byte_count = 3 /* pad */ + params + count;
5539 pSMB->DataCount = cpu_to_le16(count);
5540 pSMB->ParameterCount = cpu_to_le16(params);
5541 pSMB->TotalDataCount = pSMB->DataCount;
5542 pSMB->TotalParameterCount = pSMB->ParameterCount;
5543 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5544 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00005545 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
5546 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005547 pSMB->DataOffset = cpu_to_le16(offset);
5548 parm_data->FileSize = cpu_to_le64(size);
5549 pSMB->Fid = fid;
Steve French790fe572007-07-07 19:25:05 +00005550 if (SetAllocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005551 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5552 pSMB->InformationLevel =
5553 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5554 else
5555 pSMB->InformationLevel =
5556 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00005557 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005558 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5559 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005560 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005561 else
5562 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005563 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005564 }
5565 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005566 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005567 pSMB->ByteCount = cpu_to_le16(byte_count);
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005568 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005569 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005570 cFYI(1, "Send error in SetFileInfo (SetFileSize) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005571 }
5572
Steve French50c2f752007-07-13 00:33:32 +00005573 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005574 since file handle passed in no longer valid */
5575
5576 return rc;
5577}
5578
Steve French50c2f752007-07-13 00:33:32 +00005579/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07005580 an open handle, rather than by pathname - this is awkward due to
5581 potential access conflicts on the open, but it is unavoidable for these
5582 old servers since the only other choice is to go from 100 nanosecond DCE
5583 time and resort to the original setpathinfo level which takes the ancient
5584 DOS time format with 2 second granularity */
5585int
Steve French96daf2b2011-05-27 04:34:02 +00005586CIFSSMBSetFileInfo(const int xid, struct cifs_tcon *tcon,
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005587 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005588{
5589 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005590 char *data_offset;
5591 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005592 __u16 params, param_offset, offset, byte_count, count;
5593
Joe Perchesb6b38f72010-04-21 03:50:45 +00005594 cFYI(1, "Set Times (via SetFileInfo)");
Steve Frenchcd634992005-04-28 22:41:10 -07005595 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5596
Linus Torvalds1da177e2005-04-16 15:20:36 -07005597 if (rc)
5598 return rc;
5599
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005600 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5601 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005602
Linus Torvalds1da177e2005-04-16 15:20:36 -07005603 params = 6;
5604 pSMB->MaxSetupCount = 0;
5605 pSMB->Reserved = 0;
5606 pSMB->Flags = 0;
5607 pSMB->Timeout = 0;
5608 pSMB->Reserved2 = 0;
5609 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5610 offset = param_offset + params;
5611
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005612 data_offset = (char *)pSMB +
5613 offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005614
Steve French26f57362007-08-30 22:09:15 +00005615 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005616 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005617 /* BB find max SMB PDU from sess */
5618 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005619 pSMB->SetupCount = 1;
5620 pSMB->Reserved3 = 0;
5621 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5622 byte_count = 3 /* pad */ + params + count;
5623 pSMB->DataCount = cpu_to_le16(count);
5624 pSMB->ParameterCount = cpu_to_le16(params);
5625 pSMB->TotalDataCount = pSMB->DataCount;
5626 pSMB->TotalParameterCount = pSMB->ParameterCount;
5627 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5628 pSMB->DataOffset = cpu_to_le16(offset);
5629 pSMB->Fid = fid;
5630 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5631 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5632 else
5633 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5634 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005635 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005636 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005637 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005638 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005639 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005640 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005641
Steve French50c2f752007-07-13 00:33:32 +00005642 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005643 since file handle passed in no longer valid */
5644
5645 return rc;
5646}
5647
Jeff Layton6d22f092008-09-23 11:48:35 -04005648int
Steve French96daf2b2011-05-27 04:34:02 +00005649CIFSSMBSetFileDisposition(const int xid, struct cifs_tcon *tcon,
Jeff Layton6d22f092008-09-23 11:48:35 -04005650 bool delete_file, __u16 fid, __u32 pid_of_opener)
5651{
5652 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5653 char *data_offset;
5654 int rc = 0;
5655 __u16 params, param_offset, offset, byte_count, count;
5656
Joe Perchesb6b38f72010-04-21 03:50:45 +00005657 cFYI(1, "Set File Disposition (via SetFileInfo)");
Jeff Layton6d22f092008-09-23 11:48:35 -04005658 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5659
5660 if (rc)
5661 return rc;
5662
5663 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5664 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5665
5666 params = 6;
5667 pSMB->MaxSetupCount = 0;
5668 pSMB->Reserved = 0;
5669 pSMB->Flags = 0;
5670 pSMB->Timeout = 0;
5671 pSMB->Reserved2 = 0;
5672 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5673 offset = param_offset + params;
5674
5675 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5676
5677 count = 1;
5678 pSMB->MaxParameterCount = cpu_to_le16(2);
5679 /* BB find max SMB PDU from sess */
5680 pSMB->MaxDataCount = cpu_to_le16(1000);
5681 pSMB->SetupCount = 1;
5682 pSMB->Reserved3 = 0;
5683 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5684 byte_count = 3 /* pad */ + params + count;
5685 pSMB->DataCount = cpu_to_le16(count);
5686 pSMB->ParameterCount = cpu_to_le16(params);
5687 pSMB->TotalDataCount = pSMB->DataCount;
5688 pSMB->TotalParameterCount = pSMB->ParameterCount;
5689 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5690 pSMB->DataOffset = cpu_to_le16(offset);
5691 pSMB->Fid = fid;
5692 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5693 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005694 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton6d22f092008-09-23 11:48:35 -04005695 pSMB->ByteCount = cpu_to_le16(byte_count);
5696 *data_offset = delete_file ? 1 : 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005697 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Jeff Layton6d22f092008-09-23 11:48:35 -04005698 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005699 cFYI(1, "Send error in SetFileDisposition = %d", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005700
5701 return rc;
5702}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005703
5704int
Steve French96daf2b2011-05-27 04:34:02 +00005705CIFSSMBSetPathInfo(const int xid, struct cifs_tcon *tcon,
Jeff Layton6fc000e2008-08-02 07:26:12 -04005706 const char *fileName, const FILE_BASIC_INFO *data,
5707 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005708{
5709 TRANSACTION2_SPI_REQ *pSMB = NULL;
5710 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5711 int name_len;
5712 int rc = 0;
5713 int bytes_returned = 0;
5714 char *data_offset;
5715 __u16 params, param_offset, offset, byte_count, count;
5716
Joe Perchesb6b38f72010-04-21 03:50:45 +00005717 cFYI(1, "In SetTimes");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005718
5719SetTimesRetry:
5720 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5721 (void **) &pSMBr);
5722 if (rc)
5723 return rc;
5724
5725 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5726 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005727 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5728 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005729 name_len++; /* trailing null */
5730 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005731 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005732 name_len = strnlen(fileName, PATH_MAX);
5733 name_len++; /* trailing null */
5734 strncpy(pSMB->FileName, fileName, name_len);
5735 }
5736
5737 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005738 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005739 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005740 /* BB find max SMB PDU from sess structure BB */
5741 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005742 pSMB->MaxSetupCount = 0;
5743 pSMB->Reserved = 0;
5744 pSMB->Flags = 0;
5745 pSMB->Timeout = 0;
5746 pSMB->Reserved2 = 0;
5747 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005748 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005749 offset = param_offset + params;
5750 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5751 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5752 pSMB->DataOffset = cpu_to_le16(offset);
5753 pSMB->SetupCount = 1;
5754 pSMB->Reserved3 = 0;
5755 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5756 byte_count = 3 /* pad */ + params + count;
5757
5758 pSMB->DataCount = cpu_to_le16(count);
5759 pSMB->ParameterCount = cpu_to_le16(params);
5760 pSMB->TotalDataCount = pSMB->DataCount;
5761 pSMB->TotalParameterCount = pSMB->ParameterCount;
5762 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5763 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5764 else
5765 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5766 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005767 inc_rfc1001_len(pSMB, byte_count);
Steve French26f57362007-08-30 22:09:15 +00005768 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005769 pSMB->ByteCount = cpu_to_le16(byte_count);
5770 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5771 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005772 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005773 cFYI(1, "SetPathInfo (times) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005774
5775 cifs_buf_release(pSMB);
5776
5777 if (rc == -EAGAIN)
5778 goto SetTimesRetry;
5779
5780 return rc;
5781}
5782
5783/* Can not be used to set time stamps yet (due to old DOS time format) */
5784/* Can be used to set attributes */
5785#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5786 handling it anyway and NT4 was what we thought it would be needed for
5787 Do not delete it until we prove whether needed for Win9x though */
5788int
Steve French96daf2b2011-05-27 04:34:02 +00005789CIFSSMBSetAttrLegacy(int xid, struct cifs_tcon *tcon, char *fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005790 __u16 dos_attrs, const struct nls_table *nls_codepage)
5791{
5792 SETATTR_REQ *pSMB = NULL;
5793 SETATTR_RSP *pSMBr = NULL;
5794 int rc = 0;
5795 int bytes_returned;
5796 int name_len;
5797
Joe Perchesb6b38f72010-04-21 03:50:45 +00005798 cFYI(1, "In SetAttrLegacy");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005799
5800SetAttrLgcyRetry:
5801 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5802 (void **) &pSMBr);
5803 if (rc)
5804 return rc;
5805
5806 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5807 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005808 ConvertToUTF16((__le16 *) pSMB->fileName, fileName,
5809 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005810 name_len++; /* trailing null */
5811 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005812 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005813 name_len = strnlen(fileName, PATH_MAX);
5814 name_len++; /* trailing null */
5815 strncpy(pSMB->fileName, fileName, name_len);
5816 }
5817 pSMB->attr = cpu_to_le16(dos_attrs);
5818 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005819 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005820 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5821 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5822 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005823 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005824 cFYI(1, "Error in LegacySetAttr = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005825
5826 cifs_buf_release(pSMB);
5827
5828 if (rc == -EAGAIN)
5829 goto SetAttrLgcyRetry;
5830
5831 return rc;
5832}
5833#endif /* temporarily unneeded SetAttr legacy function */
5834
Jeff Layton654cf142009-07-09 20:02:49 -04005835static void
5836cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5837 const struct cifs_unix_set_info_args *args)
5838{
5839 u64 mode = args->mode;
5840
5841 /*
5842 * Samba server ignores set of file size to zero due to bugs in some
5843 * older clients, but we should be precise - we use SetFileSize to
5844 * set file size and do not want to truncate file size to zero
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005845 * accidentally as happened on one Samba server beta by putting
Jeff Layton654cf142009-07-09 20:02:49 -04005846 * zero instead of -1 here
5847 */
5848 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5849 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5850 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5851 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5852 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5853 data_offset->Uid = cpu_to_le64(args->uid);
5854 data_offset->Gid = cpu_to_le64(args->gid);
5855 /* better to leave device as zero when it is */
5856 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5857 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5858 data_offset->Permissions = cpu_to_le64(mode);
5859
5860 if (S_ISREG(mode))
5861 data_offset->Type = cpu_to_le32(UNIX_FILE);
5862 else if (S_ISDIR(mode))
5863 data_offset->Type = cpu_to_le32(UNIX_DIR);
5864 else if (S_ISLNK(mode))
5865 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5866 else if (S_ISCHR(mode))
5867 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5868 else if (S_ISBLK(mode))
5869 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5870 else if (S_ISFIFO(mode))
5871 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5872 else if (S_ISSOCK(mode))
5873 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5874}
5875
Linus Torvalds1da177e2005-04-16 15:20:36 -07005876int
Steve French96daf2b2011-05-27 04:34:02 +00005877CIFSSMBUnixSetFileInfo(const int xid, struct cifs_tcon *tcon,
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005878 const struct cifs_unix_set_info_args *args,
5879 u16 fid, u32 pid_of_opener)
5880{
5881 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005882 char *data_offset;
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005883 int rc = 0;
5884 u16 params, param_offset, offset, byte_count, count;
5885
Joe Perchesb6b38f72010-04-21 03:50:45 +00005886 cFYI(1, "Set Unix Info (via SetFileInfo)");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005887 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5888
5889 if (rc)
5890 return rc;
5891
5892 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5893 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5894
5895 params = 6;
5896 pSMB->MaxSetupCount = 0;
5897 pSMB->Reserved = 0;
5898 pSMB->Flags = 0;
5899 pSMB->Timeout = 0;
5900 pSMB->Reserved2 = 0;
5901 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5902 offset = param_offset + params;
5903
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005904 data_offset = (char *)pSMB +
5905 offsetof(struct smb_hdr, Protocol) + offset;
5906
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005907 count = sizeof(FILE_UNIX_BASIC_INFO);
5908
5909 pSMB->MaxParameterCount = cpu_to_le16(2);
5910 /* BB find max SMB PDU from sess */
5911 pSMB->MaxDataCount = cpu_to_le16(1000);
5912 pSMB->SetupCount = 1;
5913 pSMB->Reserved3 = 0;
5914 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5915 byte_count = 3 /* pad */ + params + count;
5916 pSMB->DataCount = cpu_to_le16(count);
5917 pSMB->ParameterCount = cpu_to_le16(params);
5918 pSMB->TotalDataCount = pSMB->DataCount;
5919 pSMB->TotalParameterCount = pSMB->ParameterCount;
5920 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5921 pSMB->DataOffset = cpu_to_le16(offset);
5922 pSMB->Fid = fid;
5923 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5924 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005925 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005926 pSMB->ByteCount = cpu_to_le16(byte_count);
5927
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005928 cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005929
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005930 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005931 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005932 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005933
5934 /* Note: On -EAGAIN error only caller can retry on handle based calls
5935 since file handle passed in no longer valid */
5936
5937 return rc;
5938}
5939
5940int
Steve French96daf2b2011-05-27 04:34:02 +00005941CIFSSMBUnixSetPathInfo(const int xid, struct cifs_tcon *tcon, char *fileName,
Jeff Layton01ea95e2009-07-09 20:02:49 -04005942 const struct cifs_unix_set_info_args *args,
5943 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005944{
5945 TRANSACTION2_SPI_REQ *pSMB = NULL;
5946 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5947 int name_len;
5948 int rc = 0;
5949 int bytes_returned = 0;
5950 FILE_UNIX_BASIC_INFO *data_offset;
5951 __u16 params, param_offset, offset, count, byte_count;
5952
Joe Perchesb6b38f72010-04-21 03:50:45 +00005953 cFYI(1, "In SetUID/GID/Mode");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005954setPermsRetry:
5955 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5956 (void **) &pSMBr);
5957 if (rc)
5958 return rc;
5959
5960 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5961 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005962 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5963 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005964 name_len++; /* trailing null */
5965 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005966 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005967 name_len = strnlen(fileName, PATH_MAX);
5968 name_len++; /* trailing null */
5969 strncpy(pSMB->FileName, fileName, name_len);
5970 }
5971
5972 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005973 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005974 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005975 /* BB find max SMB PDU from sess structure BB */
5976 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005977 pSMB->MaxSetupCount = 0;
5978 pSMB->Reserved = 0;
5979 pSMB->Flags = 0;
5980 pSMB->Timeout = 0;
5981 pSMB->Reserved2 = 0;
5982 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005983 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005984 offset = param_offset + params;
5985 data_offset =
5986 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5987 offset);
5988 memset(data_offset, 0, count);
5989 pSMB->DataOffset = cpu_to_le16(offset);
5990 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5991 pSMB->SetupCount = 1;
5992 pSMB->Reserved3 = 0;
5993 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5994 byte_count = 3 /* pad */ + params + count;
5995 pSMB->ParameterCount = cpu_to_le16(params);
5996 pSMB->DataCount = cpu_to_le16(count);
5997 pSMB->TotalParameterCount = pSMB->ParameterCount;
5998 pSMB->TotalDataCount = pSMB->DataCount;
5999 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6000 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006001 inc_rfc1001_len(pSMB, byte_count);
Steve French50c2f752007-07-13 00:33:32 +00006002
Jeff Layton654cf142009-07-09 20:02:49 -04006003 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006004
6005 pSMB->ByteCount = cpu_to_le16(byte_count);
6006 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6007 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006008 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00006009 cFYI(1, "SetPathInfo (perms) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006010
Steve French0d817bc2008-05-22 02:02:03 +00006011 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006012 if (rc == -EAGAIN)
6013 goto setPermsRetry;
6014 return rc;
6015}
6016
Linus Torvalds1da177e2005-04-16 15:20:36 -07006017#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05006018/*
6019 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
6020 * function used by listxattr and getxattr type calls. When ea_name is set,
6021 * it looks for that attribute name and stuffs that value into the EAData
6022 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
6023 * buffer. In both cases, the return value is either the length of the
6024 * resulting data or a negative error code. If EAData is a NULL pointer then
6025 * the data isn't copied to it, but the length is returned.
6026 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006027ssize_t
Steve French96daf2b2011-05-27 04:34:02 +00006028CIFSSMBQAllEAs(const int xid, struct cifs_tcon *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05006029 const unsigned char *searchName, const unsigned char *ea_name,
6030 char *EAData, size_t buf_size,
6031 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006032{
6033 /* BB assumes one setup word */
6034 TRANSACTION2_QPI_REQ *pSMB = NULL;
6035 TRANSACTION2_QPI_RSP *pSMBr = NULL;
6036 int rc = 0;
6037 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05006038 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006039 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00006040 struct fea *temp_fea;
6041 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006042 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006043 __u16 params, byte_count, data_offset;
Jeff Layton5980fc92011-07-28 12:48:26 -04006044 unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006045
Joe Perchesb6b38f72010-04-21 03:50:45 +00006046 cFYI(1, "In Query All EAs path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006047QAllEAsRetry:
6048 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6049 (void **) &pSMBr);
6050 if (rc)
6051 return rc;
6052
6053 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05006054 list_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006055 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
6056 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05006057 list_len++; /* trailing null */
6058 list_len *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006059 } else { /* BB improve the check for buffer overruns BB */
Jeff Layton6e462b92010-02-10 16:18:26 -05006060 list_len = strnlen(searchName, PATH_MAX);
6061 list_len++; /* trailing null */
6062 strncpy(pSMB->FileName, searchName, list_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006063 }
6064
Jeff Layton6e462b92010-02-10 16:18:26 -05006065 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006066 pSMB->TotalDataCount = 0;
6067 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006068 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05006069 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006070 pSMB->MaxSetupCount = 0;
6071 pSMB->Reserved = 0;
6072 pSMB->Flags = 0;
6073 pSMB->Timeout = 0;
6074 pSMB->Reserved2 = 0;
6075 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00006076 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006077 pSMB->DataCount = 0;
6078 pSMB->DataOffset = 0;
6079 pSMB->SetupCount = 1;
6080 pSMB->Reserved3 = 0;
6081 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
6082 byte_count = params + 1 /* pad */ ;
6083 pSMB->TotalParameterCount = cpu_to_le16(params);
6084 pSMB->ParameterCount = pSMB->TotalParameterCount;
6085 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
6086 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006087 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006088 pSMB->ByteCount = cpu_to_le16(byte_count);
6089
6090 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6091 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6092 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006093 cFYI(1, "Send error in QueryAllEAs = %d", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05006094 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006095 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006096
6097
6098 /* BB also check enough total bytes returned */
6099 /* BB we need to improve the validity checking
6100 of these trans2 responses */
6101
6102 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Jeff Layton820a8032011-05-04 08:05:26 -04006103 if (rc || get_bcc(&pSMBr->hdr) < 4) {
Jeff Laytonf0d38682010-02-10 16:18:26 -05006104 rc = -EIO; /* bad smb */
6105 goto QAllEAsOut;
6106 }
6107
6108 /* check that length of list is not more than bcc */
6109 /* check that each entry does not go beyond length
6110 of list */
6111 /* check that each element of each entry does not
6112 go beyond end of list */
6113 /* validate_trans2_offsets() */
6114 /* BB check if start of smb + data_offset > &bcc+ bcc */
6115
6116 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
6117 ea_response_data = (struct fealist *)
6118 (((char *) &pSMBr->hdr.Protocol) + data_offset);
6119
Jeff Layton6e462b92010-02-10 16:18:26 -05006120 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesb6b38f72010-04-21 03:50:45 +00006121 cFYI(1, "ea length %d", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05006122 if (list_len <= 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006123 cFYI(1, "empty EA list returned from server");
Jeff Laytonf0d38682010-02-10 16:18:26 -05006124 goto QAllEAsOut;
6125 }
6126
Jeff Layton0cd126b2010-02-10 16:18:26 -05006127 /* make sure list_len doesn't go past end of SMB */
Jeff Layton690c5222011-01-20 13:36:51 -05006128 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
Jeff Layton0cd126b2010-02-10 16:18:26 -05006129 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006130 cFYI(1, "EA list appears to go beyond SMB");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006131 rc = -EIO;
6132 goto QAllEAsOut;
6133 }
6134
Jeff Laytonf0d38682010-02-10 16:18:26 -05006135 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05006136 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006137 temp_fea = ea_response_data->list;
6138 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05006139 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00006140 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006141 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006142
Jeff Layton6e462b92010-02-10 16:18:26 -05006143 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006144 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006145 /* make sure we can read name_len and value_len */
6146 if (list_len < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006147 cFYI(1, "EA entry goes beyond length of list");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006148 rc = -EIO;
6149 goto QAllEAsOut;
6150 }
6151
6152 name_len = temp_fea->name_len;
6153 value_len = le16_to_cpu(temp_fea->value_len);
6154 list_len -= name_len + 1 + 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
Jeff Layton31c05192010-02-10 16:18:26 -05006161 if (ea_name) {
Jeff Layton91d065c2011-07-26 18:23:47 -04006162 if (ea_name_len == name_len &&
Jeff Laytonac423442011-10-11 06:41:32 -04006163 memcmp(ea_name, temp_ptr, name_len) == 0) {
Jeff Layton31c05192010-02-10 16:18:26 -05006164 temp_ptr += name_len + 1;
6165 rc = value_len;
6166 if (buf_size == 0)
6167 goto QAllEAsOut;
6168 if ((size_t)value_len > buf_size) {
6169 rc = -ERANGE;
6170 goto QAllEAsOut;
6171 }
6172 memcpy(EAData, temp_ptr, value_len);
6173 goto QAllEAsOut;
6174 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006175 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05006176 /* account for prefix user. and trailing null */
6177 rc += (5 + 1 + name_len);
6178 if (rc < (int) buf_size) {
6179 memcpy(EAData, "user.", 5);
6180 EAData += 5;
6181 memcpy(EAData, temp_ptr, name_len);
6182 EAData += name_len;
6183 /* null terminate name */
6184 *EAData = 0;
6185 ++EAData;
6186 } else if (buf_size == 0) {
6187 /* skip copy - calc size only */
6188 } else {
6189 /* stop before overrun buffer */
6190 rc = -ERANGE;
6191 break;
6192 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006193 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05006194 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006195 temp_fea = (struct fea *)temp_ptr;
6196 }
6197
Jeff Layton31c05192010-02-10 16:18:26 -05006198 /* didn't find the named attribute */
6199 if (ea_name)
6200 rc = -ENODATA;
6201
Jeff Laytonf0d38682010-02-10 16:18:26 -05006202QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00006203 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006204 if (rc == -EAGAIN)
6205 goto QAllEAsRetry;
6206
6207 return (ssize_t)rc;
6208}
6209
Linus Torvalds1da177e2005-04-16 15:20:36 -07006210int
Steve French96daf2b2011-05-27 04:34:02 +00006211CIFSSMBSetEA(const int xid, struct cifs_tcon *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00006212 const char *ea_name, const void *ea_value,
6213 const __u16 ea_value_len, const struct nls_table *nls_codepage,
6214 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006215{
6216 struct smb_com_transaction2_spi_req *pSMB = NULL;
6217 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
6218 struct fealist *parm_data;
6219 int name_len;
6220 int rc = 0;
6221 int bytes_returned = 0;
6222 __u16 params, param_offset, byte_count, offset, count;
6223
Joe Perchesb6b38f72010-04-21 03:50:45 +00006224 cFYI(1, "In SetEA");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006225SetEARetry:
6226 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6227 (void **) &pSMBr);
6228 if (rc)
6229 return rc;
6230
6231 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6232 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006233 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
6234 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006235 name_len++; /* trailing null */
6236 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00006237 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006238 name_len = strnlen(fileName, PATH_MAX);
6239 name_len++; /* trailing null */
6240 strncpy(pSMB->FileName, fileName, name_len);
6241 }
6242
6243 params = 6 + name_len;
6244
6245 /* done calculating parms using name_len of file name,
6246 now use name_len to calculate length of ea name
6247 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00006248 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006249 name_len = 0;
6250 else
Steve French50c2f752007-07-13 00:33:32 +00006251 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006252
Steve Frenchdae5dbd2007-12-30 23:49:57 +00006253 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006254 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006255 /* BB find max SMB PDU from sess */
6256 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006257 pSMB->MaxSetupCount = 0;
6258 pSMB->Reserved = 0;
6259 pSMB->Flags = 0;
6260 pSMB->Timeout = 0;
6261 pSMB->Reserved2 = 0;
6262 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006263 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006264 offset = param_offset + params;
6265 pSMB->InformationLevel =
6266 cpu_to_le16(SMB_SET_FILE_EA);
6267
6268 parm_data =
6269 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
6270 offset);
6271 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6272 pSMB->DataOffset = cpu_to_le16(offset);
6273 pSMB->SetupCount = 1;
6274 pSMB->Reserved3 = 0;
6275 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6276 byte_count = 3 /* pad */ + params + count;
6277 pSMB->DataCount = cpu_to_le16(count);
6278 parm_data->list_len = cpu_to_le32(count);
6279 parm_data->list[0].EA_flags = 0;
6280 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08006281 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006282 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00006283 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00006284 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006285 parm_data->list[0].name[name_len] = 0;
6286 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
6287 /* caller ensures that ea_value_len is less than 64K but
6288 we need to ensure that it fits within the smb */
6289
Steve French50c2f752007-07-13 00:33:32 +00006290 /*BB add length check to see if it would fit in
6291 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00006292 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
6293 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00006294 memcpy(parm_data->list[0].name+name_len+1,
6295 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006296
6297 pSMB->TotalDataCount = pSMB->DataCount;
6298 pSMB->ParameterCount = cpu_to_le16(params);
6299 pSMB->TotalParameterCount = pSMB->ParameterCount;
6300 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006301 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006302 pSMB->ByteCount = cpu_to_le16(byte_count);
6303 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6304 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006305 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00006306 cFYI(1, "SetPathInfo (EA) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006307
6308 cifs_buf_release(pSMB);
6309
6310 if (rc == -EAGAIN)
6311 goto SetEARetry;
6312
6313 return rc;
6314}
Linus Torvalds1da177e2005-04-16 15:20:36 -07006315#endif
Steve French0eff0e22011-02-24 05:39:23 +00006316
6317#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */
6318/*
6319 * Years ago the kernel added a "dnotify" function for Samba server,
6320 * to allow network clients (such as Windows) to display updated
6321 * lists of files in directory listings automatically when
6322 * files are added by one user when another user has the
6323 * same directory open on their desktop. The Linux cifs kernel
6324 * client hooked into the kernel side of this interface for
6325 * the same reason, but ironically when the VFS moved from
6326 * "dnotify" to "inotify" it became harder to plug in Linux
6327 * network file system clients (the most obvious use case
6328 * for notify interfaces is when multiple users can update
6329 * the contents of the same directory - exactly what network
6330 * file systems can do) although the server (Samba) could
6331 * still use it. For the short term we leave the worker
6332 * function ifdeffed out (below) until inotify is fixed
6333 * in the VFS to make it easier to plug in network file
6334 * system clients. If inotify turns out to be permanently
6335 * incompatible for network fs clients, we could instead simply
6336 * expose this config flag by adding a future cifs (and smb2) notify ioctl.
6337 */
Steve French96daf2b2011-05-27 04:34:02 +00006338int CIFSSMBNotify(const int xid, struct cifs_tcon *tcon,
Steve French0eff0e22011-02-24 05:39:23 +00006339 const int notify_subdirs, const __u16 netfid,
6340 __u32 filter, struct file *pfile, int multishot,
6341 const struct nls_table *nls_codepage)
6342{
6343 int rc = 0;
6344 struct smb_com_transaction_change_notify_req *pSMB = NULL;
6345 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
6346 struct dir_notify_req *dnotify_req;
6347 int bytes_returned;
6348
6349 cFYI(1, "In CIFSSMBNotify for file handle %d", (int)netfid);
6350 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
6351 (void **) &pSMBr);
6352 if (rc)
6353 return rc;
6354
6355 pSMB->TotalParameterCount = 0 ;
6356 pSMB->TotalDataCount = 0;
6357 pSMB->MaxParameterCount = cpu_to_le32(2);
Jeff Laytonc974bef2011-10-11 06:41:32 -04006358 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Steve French0eff0e22011-02-24 05:39:23 +00006359 pSMB->MaxSetupCount = 4;
6360 pSMB->Reserved = 0;
6361 pSMB->ParameterOffset = 0;
6362 pSMB->DataCount = 0;
6363 pSMB->DataOffset = 0;
6364 pSMB->SetupCount = 4; /* single byte does not need le conversion */
6365 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
6366 pSMB->ParameterCount = pSMB->TotalParameterCount;
6367 if (notify_subdirs)
6368 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
6369 pSMB->Reserved2 = 0;
6370 pSMB->CompletionFilter = cpu_to_le32(filter);
6371 pSMB->Fid = netfid; /* file handle always le */
6372 pSMB->ByteCount = 0;
6373
6374 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6375 (struct smb_hdr *)pSMBr, &bytes_returned,
6376 CIFS_ASYNC_OP);
6377 if (rc) {
6378 cFYI(1, "Error in Notify = %d", rc);
6379 } else {
6380 /* Add file to outstanding requests */
6381 /* BB change to kmem cache alloc */
6382 dnotify_req = kmalloc(
6383 sizeof(struct dir_notify_req),
6384 GFP_KERNEL);
6385 if (dnotify_req) {
6386 dnotify_req->Pid = pSMB->hdr.Pid;
6387 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
6388 dnotify_req->Mid = pSMB->hdr.Mid;
6389 dnotify_req->Tid = pSMB->hdr.Tid;
6390 dnotify_req->Uid = pSMB->hdr.Uid;
6391 dnotify_req->netfid = netfid;
6392 dnotify_req->pfile = pfile;
6393 dnotify_req->filter = filter;
6394 dnotify_req->multishot = multishot;
6395 spin_lock(&GlobalMid_Lock);
6396 list_add_tail(&dnotify_req->lhead,
6397 &GlobalDnotifyReqList);
6398 spin_unlock(&GlobalMid_Lock);
6399 } else
6400 rc = -ENOMEM;
6401 }
6402 cifs_buf_release(pSMB);
6403 return rc;
6404}
6405#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */