blob: 3a75ee5a6b33a65795783e633f4ff31f3f94822d [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/cifssmb.c
3 *
Steve Frenchf19159d2010-04-21 04:12:10 +00004 * Copyright (C) International Business Machines Corp., 2002,2010
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * Author(s): Steve French (sfrench@us.ibm.com)
6 *
7 * Contains the routines for constructing the SMB PDUs themselves
8 *
9 * This library is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as published
11 * by the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
17 * the GNU Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24 /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c */
25 /* These are mostly routines that operate on a pathname, or on a tree id */
26 /* (mounted volume), but there are eight handle based routines which must be */
Steve French2dd29d32007-04-23 22:07:35 +000027 /* treated slightly differently for reconnection purposes since we never */
28 /* want to reuse a stale file handle and only the caller knows the file info */
Linus Torvalds1da177e2005-04-16 15:20:36 -070029
30#include <linux/fs.h>
31#include <linux/kernel.h>
32#include <linux/vfs.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090033#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include <linux/posix_acl_xattr.h>
Jeff Laytonc28c89f2011-05-19 16:22:56 -040035#include <linux/pagemap.h>
Jeff Laytone28bc5b2011-10-19 15:30:07 -040036#include <linux/swap.h>
37#include <linux/task_io_accounting_ops.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070038#include <asm/uaccess.h>
39#include "cifspdu.h"
40#include "cifsglob.h"
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +000041#include "cifsacl.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070042#include "cifsproto.h"
43#include "cifs_unicode.h"
44#include "cifs_debug.h"
Jeff Laytone28bc5b2011-10-19 15:30:07 -040045#include "fscache.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070046
47#ifdef CONFIG_CIFS_POSIX
48static struct {
49 int index;
50 char *name;
51} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000052#ifdef CONFIG_CIFS_WEAK_PW_HASH
53 {LANMAN_PROT, "\2LM1.2X002"},
Steve French9ac00b72006-09-30 04:13:17 +000054 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000055#endif /* weak password hashing for legacy clients */
Steve French50c2f752007-07-13 00:33:32 +000056 {CIFS_PROT, "\2NT LM 0.12"},
Steve French39798772006-05-31 22:40:51 +000057 {POSIX_PROT, "\2POSIX 2"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070058 {BAD_PROT, "\2"}
59};
60#else
61static struct {
62 int index;
63 char *name;
64} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000065#ifdef CONFIG_CIFS_WEAK_PW_HASH
66 {LANMAN_PROT, "\2LM1.2X002"},
Steve French18f75ca2006-10-01 03:13:01 +000067 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000068#endif /* weak password hashing for legacy clients */
Steve French790fe572007-07-07 19:25:05 +000069 {CIFS_PROT, "\2NT LM 0.12"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070070 {BAD_PROT, "\2"}
71};
72#endif
73
Steve French39798772006-05-31 22:40:51 +000074/* define the number of elements in the cifs dialect array */
75#ifdef CONFIG_CIFS_POSIX
76#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000077#define CIFS_NUM_PROT 4
Steve French39798772006-05-31 22:40:51 +000078#else
79#define CIFS_NUM_PROT 2
80#endif /* CIFS_WEAK_PW_HASH */
81#else /* not posix */
82#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000083#define CIFS_NUM_PROT 3
Steve French39798772006-05-31 22:40:51 +000084#else
85#define CIFS_NUM_PROT 1
86#endif /* CONFIG_CIFS_WEAK_PW_HASH */
87#endif /* CIFS_POSIX */
88
Jeff Laytone28bc5b2011-10-19 15:30:07 -040089/* Forward declarations */
90static void cifs_readv_complete(struct work_struct *work);
91
Jeff Layton5d0c7b42012-07-11 09:09:36 -040092#ifdef CONFIG_HIGHMEM
93/*
94 * On arches that have high memory, kmap address space is limited. By
95 * serializing the kmap operations on those arches, we ensure that we don't
96 * end up with a bunch of threads in writeback with partially mapped page
97 * arrays, stuck waiting for kmap to come back. That situation prevents
98 * progress and can deadlock.
99 */
100static DEFINE_MUTEX(cifs_kmap_mutex);
101
102static inline void
103cifs_kmap_lock(void)
104{
105 mutex_lock(&cifs_kmap_mutex);
106}
107
108static inline void
109cifs_kmap_unlock(void)
110{
111 mutex_unlock(&cifs_kmap_mutex);
112}
113#else /* !CONFIG_HIGHMEM */
114#define cifs_kmap_lock() do { ; } while(0)
115#define cifs_kmap_unlock() do { ; } while(0)
116#endif /* CONFIG_HIGHMEM */
117
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118/* Mark as invalid, all open files on tree connections since they
119 were closed when session to server was lost */
Steve French96daf2b2011-05-27 04:34:02 +0000120static void mark_open_files_invalid(struct cifs_tcon *pTcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121{
122 struct cifsFileInfo *open_file = NULL;
Steve French790fe572007-07-07 19:25:05 +0000123 struct list_head *tmp;
124 struct list_head *tmp1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125
126/* list all files open on tree connection and mark them invalid */
Jeff Layton44772882010-10-15 15:34:03 -0400127 spin_lock(&cifs_file_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128 list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
Steve French790fe572007-07-07 19:25:05 +0000129 open_file = list_entry(tmp, struct cifsFileInfo, tlist);
Steve Frenchad8b15f2008-08-08 21:10:16 +0000130 open_file->invalidHandle = true;
Jeff Layton3bc303c2009-09-21 06:47:50 -0400131 open_file->oplock_break_cancelled = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132 }
Jeff Layton44772882010-10-15 15:34:03 -0400133 spin_unlock(&cifs_file_list_lock);
Steve French09d1db52005-04-28 22:41:08 -0700134 /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
135 to this tcon */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136}
137
Jeff Layton9162ab22009-09-03 12:07:17 -0400138/* reconnect the socket, tcon, and smb session if needed */
139static int
Steve French96daf2b2011-05-27 04:34:02 +0000140cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
Jeff Layton9162ab22009-09-03 12:07:17 -0400141{
Jeff Laytonc4a55342011-07-28 12:40:36 -0400142 int rc;
Steve French96daf2b2011-05-27 04:34:02 +0000143 struct cifs_ses *ses;
Jeff Layton9162ab22009-09-03 12:07:17 -0400144 struct TCP_Server_Info *server;
145 struct nls_table *nls_codepage;
146
147 /*
148 * SMBs NegProt, SessSetup, uLogoff do not have tcon yet so check for
149 * tcp and smb session status done differently for those three - in the
150 * calling routine
151 */
152 if (!tcon)
153 return 0;
154
155 ses = tcon->ses;
156 server = ses->server;
157
158 /*
159 * only tree disconnect, open, and write, (and ulogoff which does not
160 * have tcon) are allowed as we start force umount
161 */
162 if (tcon->tidStatus == CifsExiting) {
163 if (smb_command != SMB_COM_WRITE_ANDX &&
164 smb_command != SMB_COM_OPEN_ANDX &&
165 smb_command != SMB_COM_TREE_DISCONNECT) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000166 cFYI(1, "can not send cmd %d while umounting",
167 smb_command);
Jeff Layton9162ab22009-09-03 12:07:17 -0400168 return -ENODEV;
169 }
170 }
171
Jeff Layton9162ab22009-09-03 12:07:17 -0400172 /*
173 * Give demultiplex thread up to 10 seconds to reconnect, should be
174 * greater than cifs socket timeout which is 7 seconds
175 */
176 while (server->tcpStatus == CifsNeedReconnect) {
177 wait_event_interruptible_timeout(server->response_q,
Steve Frenchfd88ce92011-04-12 01:01:14 +0000178 (server->tcpStatus != CifsNeedReconnect), 10 * HZ);
Jeff Layton9162ab22009-09-03 12:07:17 -0400179
Steve Frenchfd88ce92011-04-12 01:01:14 +0000180 /* are we still trying to reconnect? */
Jeff Layton9162ab22009-09-03 12:07:17 -0400181 if (server->tcpStatus != CifsNeedReconnect)
182 break;
183
184 /*
185 * on "soft" mounts we wait once. Hard mounts keep
186 * retrying until process is killed or server comes
187 * back on-line
188 */
Jeff Laytond4025392011-02-07 08:54:35 -0500189 if (!tcon->retry) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000190 cFYI(1, "gave up waiting on reconnect in smb_init");
Jeff Layton9162ab22009-09-03 12:07:17 -0400191 return -EHOSTDOWN;
192 }
193 }
194
195 if (!ses->need_reconnect && !tcon->need_reconnect)
196 return 0;
197
198 nls_codepage = load_nls_default();
199
200 /*
201 * need to prevent multiple threads trying to simultaneously
202 * reconnect the same SMB session
203 */
Steve Frenchd7b619c2010-02-25 05:36:46 +0000204 mutex_lock(&ses->session_mutex);
Jeff Layton198b5682010-04-24 07:57:48 -0400205 rc = cifs_negotiate_protocol(0, ses);
206 if (rc == 0 && ses->need_reconnect)
Jeff Layton9162ab22009-09-03 12:07:17 -0400207 rc = cifs_setup_session(0, ses, nls_codepage);
208
209 /* do we need to reconnect tcon? */
210 if (rc || !tcon->need_reconnect) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000211 mutex_unlock(&ses->session_mutex);
Jeff Layton9162ab22009-09-03 12:07:17 -0400212 goto out;
213 }
214
215 mark_open_files_invalid(tcon);
216 rc = CIFSTCon(0, ses, tcon->treeName, tcon, nls_codepage);
Steve Frenchd7b619c2010-02-25 05:36:46 +0000217 mutex_unlock(&ses->session_mutex);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000218 cFYI(1, "reconnect tcon rc = %d", rc);
Jeff Layton9162ab22009-09-03 12:07:17 -0400219
220 if (rc)
221 goto out;
222
223 /*
224 * FIXME: check if wsize needs updated due to negotiated smb buffer
225 * size shrinking
226 */
227 atomic_inc(&tconInfoReconnectCount);
228
229 /* tell server Unix caps we support */
230 if (ses->capabilities & CAP_UNIX)
231 reset_cifs_unix_caps(0, tcon, NULL, NULL);
232
233 /*
234 * Removed call to reopen open files here. It is safer (and faster) to
235 * reopen files one at a time as needed in read and write.
236 *
237 * FIXME: what about file locks? don't we need to reclaim them ASAP?
238 */
239
240out:
241 /*
242 * Check if handle based operation so we know whether we can continue
243 * or not without returning to caller to reset file handle
244 */
245 switch (smb_command) {
246 case SMB_COM_READ_ANDX:
247 case SMB_COM_WRITE_ANDX:
248 case SMB_COM_CLOSE:
249 case SMB_COM_FIND_CLOSE2:
250 case SMB_COM_LOCKING_ANDX:
251 rc = -EAGAIN;
252 }
253
254 unload_nls(nls_codepage);
255 return rc;
256}
257
Steve Frenchad7a2922008-02-07 23:25:02 +0000258/* Allocate and return pointer to an SMB request buffer, and set basic
259 SMB information in the SMB header. If the return code is zero, this
260 function must have filled in request_buf pointer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261static int
Steve French96daf2b2011-05-27 04:34:02 +0000262small_smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000263 void **request_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264{
Jeff Laytonf5695992010-09-29 15:27:08 -0400265 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266
Jeff Layton9162ab22009-09-03 12:07:17 -0400267 rc = cifs_reconnect_tcon(tcon, smb_command);
Steve French790fe572007-07-07 19:25:05 +0000268 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 return rc;
270
271 *request_buf = cifs_small_buf_get();
272 if (*request_buf == NULL) {
273 /* BB should we add a retry in here if not a writepage? */
274 return -ENOMEM;
275 }
276
Steve French63135e02007-07-17 17:34:02 +0000277 header_assemble((struct smb_hdr *) *request_buf, smb_command,
Steve Frenchc18c8422007-07-18 23:21:09 +0000278 tcon, wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279
Steve French790fe572007-07-07 19:25:05 +0000280 if (tcon != NULL)
281 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700282
Jeff Laytonf5695992010-09-29 15:27:08 -0400283 return 0;
Steve French5815449d2006-02-14 01:36:20 +0000284}
285
Steve French12b3b8f2006-02-09 21:12:47 +0000286int
Steve French50c2f752007-07-13 00:33:32 +0000287small_smb_init_no_tc(const int smb_command, const int wct,
Steve French96daf2b2011-05-27 04:34:02 +0000288 struct cifs_ses *ses, void **request_buf)
Steve French12b3b8f2006-02-09 21:12:47 +0000289{
290 int rc;
Steve French50c2f752007-07-13 00:33:32 +0000291 struct smb_hdr *buffer;
Steve French12b3b8f2006-02-09 21:12:47 +0000292
Steve French5815449d2006-02-14 01:36:20 +0000293 rc = small_smb_init(smb_command, wct, NULL, request_buf);
Steve French790fe572007-07-07 19:25:05 +0000294 if (rc)
Steve French12b3b8f2006-02-09 21:12:47 +0000295 return rc;
296
Steve French04fdabe2006-02-10 05:52:50 +0000297 buffer = (struct smb_hdr *)*request_buf;
Steve French12b3b8f2006-02-09 21:12:47 +0000298 buffer->Mid = GetNextMid(ses->server);
299 if (ses->capabilities & CAP_UNICODE)
300 buffer->Flags2 |= SMBFLG2_UNICODE;
Steve French04fdabe2006-02-10 05:52:50 +0000301 if (ses->capabilities & CAP_STATUS32)
Steve French12b3b8f2006-02-09 21:12:47 +0000302 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
303
304 /* uid, tid can stay at zero as set in header assemble */
305
Steve French50c2f752007-07-13 00:33:32 +0000306 /* BB add support for turning on the signing when
Steve French12b3b8f2006-02-09 21:12:47 +0000307 this function is used after 1st of session setup requests */
308
309 return rc;
310}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311
312/* If the return code is zero, this function must fill in request_buf pointer */
313static int
Steve French96daf2b2011-05-27 04:34:02 +0000314__smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400315 void **request_buf, void **response_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317 *request_buf = cifs_buf_get();
318 if (*request_buf == NULL) {
319 /* BB should we add a retry in here if not a writepage? */
320 return -ENOMEM;
321 }
322 /* Although the original thought was we needed the response buf for */
323 /* potential retries of smb operations it turns out we can determine */
324 /* from the mid flags when the request buffer can be resent without */
325 /* having to use a second distinct buffer for the response */
Steve French790fe572007-07-07 19:25:05 +0000326 if (response_buf)
Steve French50c2f752007-07-13 00:33:32 +0000327 *response_buf = *request_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328
329 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000330 wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331
Steve French790fe572007-07-07 19:25:05 +0000332 if (tcon != NULL)
333 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700334
Jeff Laytonf5695992010-09-29 15:27:08 -0400335 return 0;
336}
337
338/* If the return code is zero, this function must fill in request_buf pointer */
339static int
Steve French96daf2b2011-05-27 04:34:02 +0000340smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400341 void **request_buf, void **response_buf)
342{
343 int rc;
344
345 rc = cifs_reconnect_tcon(tcon, smb_command);
346 if (rc)
347 return rc;
348
349 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
350}
351
352static int
Steve French96daf2b2011-05-27 04:34:02 +0000353smb_init_no_reconnect(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400354 void **request_buf, void **response_buf)
355{
356 if (tcon->ses->need_reconnect || tcon->need_reconnect)
357 return -EHOSTDOWN;
358
359 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360}
361
Steve French50c2f752007-07-13 00:33:32 +0000362static int validate_t2(struct smb_t2_rsp *pSMB)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363{
Jeff Layton12df83c2011-01-20 13:36:51 -0500364 unsigned int total_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365
Jeff Layton12df83c2011-01-20 13:36:51 -0500366 /* check for plausible wct */
367 if (pSMB->hdr.WordCount < 10)
368 goto vt2_err;
369
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 /* check for parm and data offset going beyond end of smb */
Jeff Layton12df83c2011-01-20 13:36:51 -0500371 if (get_unaligned_le16(&pSMB->t2_rsp.ParameterOffset) > 1024 ||
372 get_unaligned_le16(&pSMB->t2_rsp.DataOffset) > 1024)
373 goto vt2_err;
374
Jeff Layton12df83c2011-01-20 13:36:51 -0500375 total_size = get_unaligned_le16(&pSMB->t2_rsp.ParameterCount);
376 if (total_size >= 512)
377 goto vt2_err;
378
Jeff Laytonfd5707e2011-03-31 17:22:07 -0400379 /* check that bcc is at least as big as parms + data, and that it is
380 * less than negotiated smb buffer
381 */
Jeff Layton12df83c2011-01-20 13:36:51 -0500382 total_size += get_unaligned_le16(&pSMB->t2_rsp.DataCount);
383 if (total_size > get_bcc(&pSMB->hdr) ||
384 total_size >= CIFSMaxBufSize + MAX_CIFS_HDR_SIZE)
385 goto vt2_err;
386
387 return 0;
388vt2_err:
Steve French50c2f752007-07-13 00:33:32 +0000389 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 sizeof(struct smb_t2_rsp) + 16);
Jeff Layton12df83c2011-01-20 13:36:51 -0500391 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392}
Jeff Layton690c5222011-01-20 13:36:51 -0500393
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000394static inline void inc_rfc1001_len(void *pSMB, int count)
395{
396 struct smb_hdr *hdr = (struct smb_hdr *)pSMB;
397
398 be32_add_cpu(&hdr->smb_buf_length, count);
399}
400
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401int
Steve French96daf2b2011-05-27 04:34:02 +0000402CIFSSMBNegotiate(unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403{
404 NEGOTIATE_REQ *pSMB;
405 NEGOTIATE_RSP *pSMBr;
406 int rc = 0;
407 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000408 int i;
Steve French50c2f752007-07-13 00:33:32 +0000409 struct TCP_Server_Info *server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 u16 count;
Steve French750d1152006-06-27 06:28:30 +0000411 unsigned int secFlags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412
Steve French790fe572007-07-07 19:25:05 +0000413 if (ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414 server = ses->server;
415 else {
416 rc = -EIO;
417 return rc;
418 }
419 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
420 (void **) &pSMB, (void **) &pSMBr);
421 if (rc)
422 return rc;
Steve French750d1152006-06-27 06:28:30 +0000423
424 /* if any of auth flags (ie not sign or seal) are overriden use them */
Steve French790fe572007-07-07 19:25:05 +0000425 if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
Steve French762e5ab2007-06-28 18:41:42 +0000426 secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
Steve French750d1152006-06-27 06:28:30 +0000427 else /* if override flags set only sign/seal OR them with global auth */
Jeff Layton04912d62010-04-24 07:57:45 -0400428 secFlags = global_secflags | ses->overrideSecFlg;
Steve French750d1152006-06-27 06:28:30 +0000429
Joe Perchesb6b38f72010-04-21 03:50:45 +0000430 cFYI(1, "secFlags 0x%x", secFlags);
Steve Frenchf40c5622006-06-28 00:13:38 +0000431
Steve French1982c342005-08-17 12:38:22 -0700432 pSMB->hdr.Mid = GetNextMid(server);
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000433 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
Steve Frencha0136892007-10-04 20:05:09 +0000434
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000435 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
Steve French254e55e2006-06-04 05:53:15 +0000436 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Steve Frencha0136892007-10-04 20:05:09 +0000437 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000438 cFYI(1, "Kerberos only mechanism, enable extended security");
Steve Frencha0136892007-10-04 20:05:09 +0000439 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Jeff Laytonb4d6fcf2011-01-07 11:30:28 -0500440 } else if ((secFlags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP)
Steve Frenchac683922009-05-06 04:16:04 +0000441 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
442 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_NTLMSSP) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000443 cFYI(1, "NTLMSSP only mechanism, enable extended security");
Steve Frenchac683922009-05-06 04:16:04 +0000444 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
445 }
Steve French50c2f752007-07-13 00:33:32 +0000446
Steve French39798772006-05-31 22:40:51 +0000447 count = 0;
Steve French50c2f752007-07-13 00:33:32 +0000448 for (i = 0; i < CIFS_NUM_PROT; i++) {
Steve French39798772006-05-31 22:40:51 +0000449 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
450 count += strlen(protocols[i].name) + 1;
451 /* null at end of source and target buffers anyway */
452 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000453 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 pSMB->ByteCount = cpu_to_le16(count);
455
456 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
457 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French50c2f752007-07-13 00:33:32 +0000458 if (rc != 0)
Steve French254e55e2006-06-04 05:53:15 +0000459 goto neg_err_exit;
460
Jeff Layton9bf67e52010-04-24 07:57:46 -0400461 server->dialect = le16_to_cpu(pSMBr->DialectIndex);
462 cFYI(1, "Dialect: %d", server->dialect);
Steve French254e55e2006-06-04 05:53:15 +0000463 /* Check wct = 1 error case */
Jeff Layton9bf67e52010-04-24 07:57:46 -0400464 if ((pSMBr->hdr.WordCount < 13) || (server->dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000465 /* core returns wct = 1, but we do not ask for core - otherwise
Steve French50c2f752007-07-13 00:33:32 +0000466 small wct just comes when dialect index is -1 indicating we
Steve French254e55e2006-06-04 05:53:15 +0000467 could not negotiate a common dialect */
468 rc = -EOPNOTSUPP;
469 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000470#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French790fe572007-07-07 19:25:05 +0000471 } else if ((pSMBr->hdr.WordCount == 13)
Jeff Layton9bf67e52010-04-24 07:57:46 -0400472 && ((server->dialect == LANMAN_PROT)
473 || (server->dialect == LANMAN2_PROT))) {
Steve Frenchb815f1e2006-10-02 05:53:29 +0000474 __s16 tmp;
Steve French50c2f752007-07-13 00:33:32 +0000475 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
Steve French254e55e2006-06-04 05:53:15 +0000476
Steve French790fe572007-07-07 19:25:05 +0000477 if ((secFlags & CIFSSEC_MAY_LANMAN) ||
Steve French750d1152006-06-27 06:28:30 +0000478 (secFlags & CIFSSEC_MAY_PLNTXT))
Steve French254e55e2006-06-04 05:53:15 +0000479 server->secType = LANMAN;
480 else {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000481 cERROR(1, "mount failed weak security disabled"
482 " in /proc/fs/cifs/SecurityFlags");
Steve French39798772006-05-31 22:40:51 +0000483 rc = -EOPNOTSUPP;
484 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000485 }
Steve French96daf2b2011-05-27 04:34:02 +0000486 server->sec_mode = (__u8)le16_to_cpu(rsp->SecurityMode);
Pavel Shilovsky10b9b982012-03-20 12:55:09 +0300487 server->maxReq = min_t(unsigned int,
488 le16_to_cpu(rsp->MaxMpxCount),
489 cifs_max_pending);
Pavel Shilovsky2d86dbc2012-02-06 15:59:18 +0400490 cifs_set_credits(server, server->maxReq);
Jeff Laytonc974bef2011-10-11 06:41:32 -0400491 server->maxBuf = le16_to_cpu(rsp->MaxBufSize);
Steve Frencheca6acf2009-02-20 05:43:09 +0000492 server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
Steve French254e55e2006-06-04 05:53:15 +0000493 /* even though we do not use raw we might as well set this
494 accurately, in case we ever find a need for it */
Steve French790fe572007-07-07 19:25:05 +0000495 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
Steve Frencheca6acf2009-02-20 05:43:09 +0000496 server->max_rw = 0xFF00;
Steve French254e55e2006-06-04 05:53:15 +0000497 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
498 } else {
Steve Frencheca6acf2009-02-20 05:43:09 +0000499 server->max_rw = 0;/* do not need to use raw anyway */
Steve French254e55e2006-06-04 05:53:15 +0000500 server->capabilities = CAP_MPX_MODE;
501 }
Steve Frenchb815f1e2006-10-02 05:53:29 +0000502 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
Steve French1a70d652006-10-02 05:59:18 +0000503 if (tmp == -1) {
Steve French25ee4a92006-09-30 00:54:23 +0000504 /* OS/2 often does not set timezone therefore
505 * we must use server time to calc time zone.
Steve Frenchb815f1e2006-10-02 05:53:29 +0000506 * Could deviate slightly from the right zone.
507 * Smallest defined timezone difference is 15 minutes
508 * (i.e. Nepal). Rounding up/down is done to match
509 * this requirement.
Steve French25ee4a92006-09-30 00:54:23 +0000510 */
Steve Frenchb815f1e2006-10-02 05:53:29 +0000511 int val, seconds, remain, result;
Steve French25ee4a92006-09-30 00:54:23 +0000512 struct timespec ts, utc;
513 utc = CURRENT_TIME;
Jeff Laytonc4a2c082009-05-27 09:37:33 -0400514 ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
515 rsp->SrvTime.Time, 0);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000516 cFYI(1, "SrvTime %d sec since 1970 (utc: %d) diff: %d",
Steve French50c2f752007-07-13 00:33:32 +0000517 (int)ts.tv_sec, (int)utc.tv_sec,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000518 (int)(utc.tv_sec - ts.tv_sec));
Steve Frenchb815f1e2006-10-02 05:53:29 +0000519 val = (int)(utc.tv_sec - ts.tv_sec);
Andre Haupt8594c152007-08-30 20:18:41 +0000520 seconds = abs(val);
Steve French947a5062006-10-02 05:55:25 +0000521 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
Steve Frenchb815f1e2006-10-02 05:53:29 +0000522 remain = seconds % MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000523 if (remain >= (MIN_TZ_ADJ / 2))
Steve Frenchb815f1e2006-10-02 05:53:29 +0000524 result += MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000525 if (val < 0)
Steve Frenchad7a2922008-02-07 23:25:02 +0000526 result = -result;
Steve Frenchb815f1e2006-10-02 05:53:29 +0000527 server->timeAdj = result;
Steve French25ee4a92006-09-30 00:54:23 +0000528 } else {
Steve Frenchb815f1e2006-10-02 05:53:29 +0000529 server->timeAdj = (int)tmp;
530 server->timeAdj *= 60; /* also in seconds */
Steve French25ee4a92006-09-30 00:54:23 +0000531 }
Joe Perchesb6b38f72010-04-21 03:50:45 +0000532 cFYI(1, "server->timeAdj: %d seconds", server->timeAdj);
Steve French25ee4a92006-09-30 00:54:23 +0000533
Steve French39798772006-05-31 22:40:51 +0000534
Steve French254e55e2006-06-04 05:53:15 +0000535 /* BB get server time for time conversions and add
Steve French50c2f752007-07-13 00:33:32 +0000536 code to use it and timezone since this is not UTC */
Steve French39798772006-05-31 22:40:51 +0000537
Steve French50c2f752007-07-13 00:33:32 +0000538 if (rsp->EncryptionKeyLength ==
Steve French25ee4a92006-09-30 00:54:23 +0000539 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500540 memcpy(ses->server->cryptkey, rsp->EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000541 CIFS_CRYPTO_KEY_SIZE);
Steve French96daf2b2011-05-27 04:34:02 +0000542 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
Steve French254e55e2006-06-04 05:53:15 +0000543 rc = -EIO; /* need cryptkey unless plain text */
544 goto neg_err_exit;
545 }
Steve French39798772006-05-31 22:40:51 +0000546
Steve Frenchf19159d2010-04-21 04:12:10 +0000547 cFYI(1, "LANMAN negotiated");
Steve French254e55e2006-06-04 05:53:15 +0000548 /* we will not end up setting signing flags - as no signing
549 was in LANMAN and server did not return the flags on */
550 goto signing_check;
Steve French7c7b25b2006-06-01 19:20:10 +0000551#else /* weak security disabled */
Steve French790fe572007-07-07 19:25:05 +0000552 } else if (pSMBr->hdr.WordCount == 13) {
Steve Frenchf19159d2010-04-21 04:12:10 +0000553 cERROR(1, "mount failed, cifs module not built "
554 "with CIFS_WEAK_PW_HASH support");
Dan Carpenter8212cf72010-03-15 11:22:26 +0300555 rc = -EOPNOTSUPP;
Steve French7c7b25b2006-06-01 19:20:10 +0000556#endif /* WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000557 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000558 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000559 /* unknown wct */
560 rc = -EOPNOTSUPP;
561 goto neg_err_exit;
562 }
563 /* else wct == 17 NTLM */
Steve French96daf2b2011-05-27 04:34:02 +0000564 server->sec_mode = pSMBr->SecurityMode;
565 if ((server->sec_mode & SECMODE_USER) == 0)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000566 cFYI(1, "share mode security");
Steve French39798772006-05-31 22:40:51 +0000567
Steve French96daf2b2011-05-27 04:34:02 +0000568 if ((server->sec_mode & SECMODE_PW_ENCRYPT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000569#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French750d1152006-06-27 06:28:30 +0000570 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000571#endif /* CIFS_WEAK_PW_HASH */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000572 cERROR(1, "Server requests plain text password"
573 " but client support disabled");
Steve French9312f672006-06-04 22:21:07 +0000574
Steve French790fe572007-07-07 19:25:05 +0000575 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
Steve French254e55e2006-06-04 05:53:15 +0000576 server->secType = NTLMv2;
Steve French790fe572007-07-07 19:25:05 +0000577 else if (secFlags & CIFSSEC_MAY_NTLM)
Steve French254e55e2006-06-04 05:53:15 +0000578 server->secType = NTLM;
Steve French790fe572007-07-07 19:25:05 +0000579 else if (secFlags & CIFSSEC_MAY_NTLMV2)
Steve Frenchf40c5622006-06-28 00:13:38 +0000580 server->secType = NTLMv2;
Steve Frencha0136892007-10-04 20:05:09 +0000581 else if (secFlags & CIFSSEC_MAY_KRB5)
582 server->secType = Kerberos;
Steve Frenchac683922009-05-06 04:16:04 +0000583 else if (secFlags & CIFSSEC_MAY_NTLMSSP)
Steve Frenchf46c7232009-06-25 03:04:20 +0000584 server->secType = RawNTLMSSP;
Steve Frencha0136892007-10-04 20:05:09 +0000585 else if (secFlags & CIFSSEC_MAY_LANMAN)
586 server->secType = LANMAN;
Steve Frencha0136892007-10-04 20:05:09 +0000587 else {
588 rc = -EOPNOTSUPP;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000589 cERROR(1, "Invalid security type");
Steve Frencha0136892007-10-04 20:05:09 +0000590 goto neg_err_exit;
591 }
592 /* else ... any others ...? */
Steve French7c7b25b2006-06-01 19:20:10 +0000593
Steve French254e55e2006-06-04 05:53:15 +0000594 /* one byte, so no need to convert this or EncryptionKeyLen from
595 little endian */
Pavel Shilovsky10b9b982012-03-20 12:55:09 +0300596 server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount),
597 cifs_max_pending);
Pavel Shilovsky2d86dbc2012-02-06 15:59:18 +0400598 cifs_set_credits(server, server->maxReq);
Steve French254e55e2006-06-04 05:53:15 +0000599 /* probably no need to store and check maxvcs */
Jeff Laytonc974bef2011-10-11 06:41:32 -0400600 server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize);
Steve Frencheca6acf2009-02-20 05:43:09 +0000601 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000602 cFYI(DBG2, "Max buf = %d", ses->server->maxBuf);
Steve French254e55e2006-06-04 05:53:15 +0000603 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e2006-10-02 05:53:29 +0000604 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
605 server->timeAdj *= 60;
Steve French254e55e2006-06-04 05:53:15 +0000606 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500607 memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000608 CIFS_CRYPTO_KEY_SIZE);
Steve French07cc6cf2011-05-27 04:12:29 +0000609 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC ||
610 server->capabilities & CAP_EXTENDED_SECURITY) &&
611 (pSMBr->EncryptionKeyLength == 0)) {
Steve French254e55e2006-06-04 05:53:15 +0000612 /* decode security blob */
Jeff Layton820a8032011-05-04 08:05:26 -0400613 count = get_bcc(&pSMBr->hdr);
Jeff Laytone187e442007-10-16 17:10:44 +0000614 if (count < 16) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 rc = -EIO;
Jeff Laytone187e442007-10-16 17:10:44 +0000616 goto neg_err_exit;
617 }
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530618 spin_lock(&cifs_tcp_ses_lock);
Jeff Laytone7ddee92008-11-14 13:44:38 -0500619 if (server->srv_count > 1) {
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530620 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000621 if (memcmp(server->server_GUID,
622 pSMBr->u.extended_response.
623 GUID, 16) != 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000624 cFYI(1, "server UID changed");
Steve French254e55e2006-06-04 05:53:15 +0000625 memcpy(server->server_GUID,
Jeff Laytone187e442007-10-16 17:10:44 +0000626 pSMBr->u.extended_response.GUID,
627 16);
628 }
Jeff Laytone7ddee92008-11-14 13:44:38 -0500629 } else {
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530630 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000631 memcpy(server->server_GUID,
632 pSMBr->u.extended_response.GUID, 16);
Jeff Laytone7ddee92008-11-14 13:44:38 -0500633 }
Jeff Laytone187e442007-10-16 17:10:44 +0000634
635 if (count == 16) {
636 server->secType = RawNTLMSSP;
Steve French254e55e2006-06-04 05:53:15 +0000637 } else {
638 rc = decode_negTokenInit(pSMBr->u.extended_response.
Jeff Layton26efa0b2010-04-24 07:57:49 -0400639 SecurityBlob, count - 16,
640 server);
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000641 if (rc == 1)
Jeff Laytone5459372007-11-03 05:11:06 +0000642 rc = 0;
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000643 else
Steve French254e55e2006-06-04 05:53:15 +0000644 rc = -EINVAL;
Shirish Pargaonkar2b149f12010-09-18 22:02:18 -0500645 if (server->secType == Kerberos) {
646 if (!server->sec_kerberos &&
647 !server->sec_mskerberos)
648 rc = -EOPNOTSUPP;
649 } else if (server->secType == RawNTLMSSP) {
650 if (!server->sec_ntlmssp)
651 rc = -EOPNOTSUPP;
652 } else
653 rc = -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 }
Steve French96daf2b2011-05-27 04:34:02 +0000655 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
Steve French07cc6cf2011-05-27 04:12:29 +0000656 rc = -EIO; /* no crypt key only if plain text pwd */
657 goto neg_err_exit;
Steve French254e55e2006-06-04 05:53:15 +0000658 } else
659 server->capabilities &= ~CAP_EXTENDED_SECURITY;
660
Steve French6344a422006-06-12 04:18:35 +0000661#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French254e55e2006-06-04 05:53:15 +0000662signing_check:
Steve French6344a422006-06-12 04:18:35 +0000663#endif
Steve French762e5ab2007-06-28 18:41:42 +0000664 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
665 /* MUST_SIGN already includes the MAY_SIGN FLAG
666 so if this is zero it means that signing is disabled */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000667 cFYI(1, "Signing disabled");
Steve French96daf2b2011-05-27 04:34:02 +0000668 if (server->sec_mode & SECMODE_SIGN_REQUIRED) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000669 cERROR(1, "Server requires "
Jeff Layton7111d212007-10-16 16:50:25 +0000670 "packet signing to be enabled in "
Joe Perchesb6b38f72010-04-21 03:50:45 +0000671 "/proc/fs/cifs/SecurityFlags.");
Steve Frenchabb63d62007-10-18 02:58:40 +0000672 rc = -EOPNOTSUPP;
673 }
Steve French96daf2b2011-05-27 04:34:02 +0000674 server->sec_mode &=
Steve French254e55e2006-06-04 05:53:15 +0000675 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Steve French762e5ab2007-06-28 18:41:42 +0000676 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
677 /* signing required */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000678 cFYI(1, "Must sign - secFlags 0x%x", secFlags);
Steve French96daf2b2011-05-27 04:34:02 +0000679 if ((server->sec_mode &
Steve French762e5ab2007-06-28 18:41:42 +0000680 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000681 cERROR(1, "signing required but server lacks support");
Jeff38c10a12007-07-06 21:10:07 +0000682 rc = -EOPNOTSUPP;
Steve French762e5ab2007-06-28 18:41:42 +0000683 } else
Steve French96daf2b2011-05-27 04:34:02 +0000684 server->sec_mode |= SECMODE_SIGN_REQUIRED;
Steve French762e5ab2007-06-28 18:41:42 +0000685 } else {
686 /* signing optional ie CIFSSEC_MAY_SIGN */
Steve French96daf2b2011-05-27 04:34:02 +0000687 if ((server->sec_mode & SECMODE_SIGN_REQUIRED) == 0)
688 server->sec_mode &=
Steve French254e55e2006-06-04 05:53:15 +0000689 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 }
Steve French50c2f752007-07-13 00:33:32 +0000691
692neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700693 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000694
Joe Perchesb6b38f72010-04-21 03:50:45 +0000695 cFYI(1, "negprot rc %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 return rc;
697}
698
699int
Steve French96daf2b2011-05-27 04:34:02 +0000700CIFSSMBTDis(const int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701{
702 struct smb_hdr *smb_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704
Joe Perchesb6b38f72010-04-21 03:50:45 +0000705 cFYI(1, "In tree disconnect");
Jeff Laytonf1987b42008-11-15 11:12:47 -0500706
707 /* BB: do we need to check this? These should never be NULL. */
708 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
709 return -EIO;
710
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 /*
Jeff Laytonf1987b42008-11-15 11:12:47 -0500712 * No need to return error on this operation if tid invalidated and
713 * closed on server already e.g. due to tcp session crashing. Also,
714 * the tcon is no longer on the list, so no need to take lock before
715 * checking this.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 */
Steve French268875b2009-06-25 00:29:21 +0000717 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
Steve French50c2f752007-07-13 00:33:32 +0000718 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719
Steve French50c2f752007-07-13 00:33:32 +0000720 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700721 (void **)&smb_buffer);
Jeff Laytonf1987b42008-11-15 11:12:47 -0500722 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 return rc;
Steve French133672e2007-11-13 22:41:37 +0000724
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400725 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)smb_buffer, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000727 cFYI(1, "Tree disconnect failed %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728
Steve French50c2f752007-07-13 00:33:32 +0000729 /* No need to return error on this operation if tid invalidated and
Jeff Laytonf1987b42008-11-15 11:12:47 -0500730 closed on server already e.g. due to tcp session crashing */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731 if (rc == -EAGAIN)
732 rc = 0;
733
734 return rc;
735}
736
Jeff Layton766fdbb2011-01-11 07:24:21 -0500737/*
738 * This is a no-op for now. We're not really interested in the reply, but
739 * rather in the fact that the server sent one and that server->lstrp
740 * gets updated.
741 *
742 * FIXME: maybe we should consider checking that the reply matches request?
743 */
744static void
745cifs_echo_callback(struct mid_q_entry *mid)
746{
747 struct TCP_Server_Info *server = mid->callback_data;
748
749 DeleteMidQEntry(mid);
Pavel Shilovsky2d86dbc2012-02-06 15:59:18 +0400750 cifs_add_credits(server, 1);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500751}
752
753int
754CIFSSMBEcho(struct TCP_Server_Info *server)
755{
756 ECHO_REQ *smb;
757 int rc = 0;
Jeff Laytonfcc31cb2011-05-19 16:22:53 -0400758 struct kvec iov;
Jeff Layton766fdbb2011-01-11 07:24:21 -0500759
760 cFYI(1, "In echo request");
761
762 rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
763 if (rc)
764 return rc;
765
766 /* set up echo request */
Steve French5443d132011-03-13 05:08:25 +0000767 smb->hdr.Tid = 0xffff;
Jeff Layton99d86c82011-01-20 21:19:25 -0500768 smb->hdr.WordCount = 1;
769 put_unaligned_le16(1, &smb->EchoCount);
Jeff Layton820a8032011-05-04 08:05:26 -0400770 put_bcc(1, &smb->hdr);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500771 smb->Data[0] = 'a';
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000772 inc_rfc1001_len(smb, 3);
Jeff Laytonfcc31cb2011-05-19 16:22:53 -0400773 iov.iov_base = smb;
774 iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
Jeff Layton766fdbb2011-01-11 07:24:21 -0500775
Jeff Layton44d22d82011-10-19 15:29:49 -0400776 rc = cifs_call_async(server, &iov, 1, NULL, cifs_echo_callback,
777 server, true);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500778 if (rc)
779 cFYI(1, "Echo request failed: %d", rc);
780
781 cifs_small_buf_release(smb);
782
783 return rc;
784}
785
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786int
Steve French96daf2b2011-05-27 04:34:02 +0000787CIFSSMBLogoff(const int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 LOGOFF_ANDX_REQ *pSMB;
790 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791
Joe Perchesb6b38f72010-04-21 03:50:45 +0000792 cFYI(1, "In SMBLogoff for session disconnect");
Jeff Layton14fbf502008-11-14 13:53:46 -0500793
794 /*
795 * BB: do we need to check validity of ses and server? They should
796 * always be valid since we have an active reference. If not, that
797 * should probably be a BUG()
798 */
799 if (!ses || !ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800 return -EIO;
801
Steve Frenchd7b619c2010-02-25 05:36:46 +0000802 mutex_lock(&ses->session_mutex);
Steve French3b795212008-11-13 19:45:32 +0000803 if (ses->need_reconnect)
804 goto session_already_dead; /* no need to send SMBlogoff if uid
805 already closed due to reconnect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
807 if (rc) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000808 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 return rc;
810 }
811
Steve French3b795212008-11-13 19:45:32 +0000812 pSMB->hdr.Mid = GetNextMid(ses->server);
Steve French1982c342005-08-17 12:38:22 -0700813
Steve French96daf2b2011-05-27 04:34:02 +0000814 if (ses->server->sec_mode &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
816 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817
818 pSMB->hdr.Uid = ses->Suid;
819
820 pSMB->AndXCommand = 0xFF;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400821 rc = SendReceiveNoRsp(xid, ses, (char *) pSMB, 0);
Steve French3b795212008-11-13 19:45:32 +0000822session_already_dead:
Steve Frenchd7b619c2010-02-25 05:36:46 +0000823 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824
825 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000826 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 error */
828 if (rc == -EAGAIN)
829 rc = 0;
830 return rc;
831}
832
833int
Steve French96daf2b2011-05-27 04:34:02 +0000834CIFSPOSIXDelFile(const int xid, struct cifs_tcon *tcon, const char *fileName,
Steve French2d785a52007-07-15 01:48:57 +0000835 __u16 type, const struct nls_table *nls_codepage, int remap)
836{
837 TRANSACTION2_SPI_REQ *pSMB = NULL;
838 TRANSACTION2_SPI_RSP *pSMBr = NULL;
839 struct unlink_psx_rq *pRqD;
840 int name_len;
841 int rc = 0;
842 int bytes_returned = 0;
843 __u16 params, param_offset, offset, byte_count;
844
Joe Perchesb6b38f72010-04-21 03:50:45 +0000845 cFYI(1, "In POSIX delete");
Steve French2d785a52007-07-15 01:48:57 +0000846PsxDelete:
847 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
848 (void **) &pSMBr);
849 if (rc)
850 return rc;
851
852 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
853 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -0600854 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
855 PATH_MAX, nls_codepage, remap);
Steve French2d785a52007-07-15 01:48:57 +0000856 name_len++; /* trailing null */
857 name_len *= 2;
858 } else { /* BB add path length overrun check */
859 name_len = strnlen(fileName, PATH_MAX);
860 name_len++; /* trailing null */
861 strncpy(pSMB->FileName, fileName, name_len);
862 }
863
864 params = 6 + name_len;
865 pSMB->MaxParameterCount = cpu_to_le16(2);
866 pSMB->MaxDataCount = 0; /* BB double check this with jra */
867 pSMB->MaxSetupCount = 0;
868 pSMB->Reserved = 0;
869 pSMB->Flags = 0;
870 pSMB->Timeout = 0;
871 pSMB->Reserved2 = 0;
872 param_offset = offsetof(struct smb_com_transaction2_spi_req,
873 InformationLevel) - 4;
874 offset = param_offset + params;
875
876 /* Setup pointer to Request Data (inode type) */
877 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
878 pRqD->type = cpu_to_le16(type);
879 pSMB->ParameterOffset = cpu_to_le16(param_offset);
880 pSMB->DataOffset = cpu_to_le16(offset);
881 pSMB->SetupCount = 1;
882 pSMB->Reserved3 = 0;
883 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
884 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
885
886 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
887 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
888 pSMB->ParameterCount = cpu_to_le16(params);
889 pSMB->TotalParameterCount = pSMB->ParameterCount;
890 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
891 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000892 inc_rfc1001_len(pSMB, byte_count);
Steve French2d785a52007-07-15 01:48:57 +0000893 pSMB->ByteCount = cpu_to_le16(byte_count);
894 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
895 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000896 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000897 cFYI(1, "Posix delete returned %d", rc);
Steve French2d785a52007-07-15 01:48:57 +0000898 cifs_buf_release(pSMB);
899
900 cifs_stats_inc(&tcon->num_deletes);
901
902 if (rc == -EAGAIN)
903 goto PsxDelete;
904
905 return rc;
906}
907
908int
Steve French96daf2b2011-05-27 04:34:02 +0000909CIFSSMBDelFile(const int xid, struct cifs_tcon *tcon, const char *fileName,
Steve French737b7582005-04-28 22:41:06 -0700910 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911{
912 DELETE_FILE_REQ *pSMB = NULL;
913 DELETE_FILE_RSP *pSMBr = NULL;
914 int rc = 0;
915 int bytes_returned;
916 int name_len;
917
918DelFileRetry:
919 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
920 (void **) &pSMBr);
921 if (rc)
922 return rc;
923
924 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
925 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -0600926 cifsConvertToUTF16((__le16 *) pSMB->fileName, fileName,
927 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928 name_len++; /* trailing null */
929 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700930 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931 name_len = strnlen(fileName, PATH_MAX);
932 name_len++; /* trailing null */
933 strncpy(pSMB->fileName, fileName, name_len);
934 }
935 pSMB->SearchAttributes =
936 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
937 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000938 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939 pSMB->ByteCount = cpu_to_le16(name_len + 1);
940 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
941 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700942 cifs_stats_inc(&tcon->num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000943 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000944 cFYI(1, "Error in RMFile = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945
946 cifs_buf_release(pSMB);
947 if (rc == -EAGAIN)
948 goto DelFileRetry;
949
950 return rc;
951}
952
953int
Steve French96daf2b2011-05-27 04:34:02 +0000954CIFSSMBRmDir(const int xid, struct cifs_tcon *tcon, const char *dirName,
Steve French737b7582005-04-28 22:41:06 -0700955 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956{
957 DELETE_DIRECTORY_REQ *pSMB = NULL;
958 DELETE_DIRECTORY_RSP *pSMBr = NULL;
959 int rc = 0;
960 int bytes_returned;
961 int name_len;
962
Joe Perchesb6b38f72010-04-21 03:50:45 +0000963 cFYI(1, "In CIFSSMBRmDir");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964RmDirRetry:
965 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
966 (void **) &pSMBr);
967 if (rc)
968 return rc;
969
970 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -0600971 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, dirName,
972 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973 name_len++; /* trailing null */
974 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700975 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 name_len = strnlen(dirName, PATH_MAX);
977 name_len++; /* trailing null */
978 strncpy(pSMB->DirName, dirName, name_len);
979 }
980
981 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000982 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 pSMB->ByteCount = cpu_to_le16(name_len + 1);
984 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
985 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700986 cifs_stats_inc(&tcon->num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000987 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000988 cFYI(1, "Error in RMDir = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989
990 cifs_buf_release(pSMB);
991 if (rc == -EAGAIN)
992 goto RmDirRetry;
993 return rc;
994}
995
996int
Steve French96daf2b2011-05-27 04:34:02 +0000997CIFSSMBMkDir(const int xid, struct cifs_tcon *tcon,
Steve French737b7582005-04-28 22:41:06 -0700998 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999{
1000 int rc = 0;
1001 CREATE_DIRECTORY_REQ *pSMB = NULL;
1002 CREATE_DIRECTORY_RSP *pSMBr = NULL;
1003 int bytes_returned;
1004 int name_len;
1005
Joe Perchesb6b38f72010-04-21 03:50:45 +00001006 cFYI(1, "In CIFSSMBMkDir");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007MkDirRetry:
1008 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
1009 (void **) &pSMBr);
1010 if (rc)
1011 return rc;
1012
1013 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06001014 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
1015 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016 name_len++; /* trailing null */
1017 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -07001018 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019 name_len = strnlen(name, PATH_MAX);
1020 name_len++; /* trailing null */
1021 strncpy(pSMB->DirName, name, name_len);
1022 }
1023
1024 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001025 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026 pSMB->ByteCount = cpu_to_le16(name_len + 1);
1027 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1028 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001029 cifs_stats_inc(&tcon->num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +00001030 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001031 cFYI(1, "Error in Mkdir = %d", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07001032
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033 cifs_buf_release(pSMB);
1034 if (rc == -EAGAIN)
1035 goto MkDirRetry;
1036 return rc;
1037}
1038
Steve French2dd29d32007-04-23 22:07:35 +00001039int
Steve French96daf2b2011-05-27 04:34:02 +00001040CIFSPOSIXCreate(const int xid, struct cifs_tcon *tcon, __u32 posix_flags,
Steve Frenchad7a2922008-02-07 23:25:02 +00001041 __u64 mode, __u16 *netfid, FILE_UNIX_BASIC_INFO *pRetData,
Steve French50c2f752007-07-13 00:33:32 +00001042 __u32 *pOplock, const char *name,
Steve French2dd29d32007-04-23 22:07:35 +00001043 const struct nls_table *nls_codepage, int remap)
1044{
1045 TRANSACTION2_SPI_REQ *pSMB = NULL;
1046 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1047 int name_len;
1048 int rc = 0;
1049 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001050 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +00001051 OPEN_PSX_REQ *pdata;
1052 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +00001053
Joe Perchesb6b38f72010-04-21 03:50:45 +00001054 cFYI(1, "In POSIX Create");
Steve French2dd29d32007-04-23 22:07:35 +00001055PsxCreat:
1056 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1057 (void **) &pSMBr);
1058 if (rc)
1059 return rc;
1060
1061 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1062 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001063 cifsConvertToUTF16((__le16 *) pSMB->FileName, name,
1064 PATH_MAX, nls_codepage, remap);
Steve French2dd29d32007-04-23 22:07:35 +00001065 name_len++; /* trailing null */
1066 name_len *= 2;
1067 } else { /* BB improve the check for buffer overruns BB */
1068 name_len = strnlen(name, PATH_MAX);
1069 name_len++; /* trailing null */
1070 strncpy(pSMB->FileName, name, name_len);
1071 }
1072
1073 params = 6 + name_len;
1074 count = sizeof(OPEN_PSX_REQ);
1075 pSMB->MaxParameterCount = cpu_to_le16(2);
1076 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1077 pSMB->MaxSetupCount = 0;
1078 pSMB->Reserved = 0;
1079 pSMB->Flags = 0;
1080 pSMB->Timeout = 0;
1081 pSMB->Reserved2 = 0;
1082 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001083 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001084 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001085 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001086 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001087 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001088 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001089 pdata->OpenFlags = cpu_to_le32(*pOplock);
1090 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1091 pSMB->DataOffset = cpu_to_le16(offset);
1092 pSMB->SetupCount = 1;
1093 pSMB->Reserved3 = 0;
1094 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1095 byte_count = 3 /* pad */ + params + count;
1096
1097 pSMB->DataCount = cpu_to_le16(count);
1098 pSMB->ParameterCount = cpu_to_le16(params);
1099 pSMB->TotalDataCount = pSMB->DataCount;
1100 pSMB->TotalParameterCount = pSMB->ParameterCount;
1101 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1102 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001103 inc_rfc1001_len(pSMB, byte_count);
Steve French2dd29d32007-04-23 22:07:35 +00001104 pSMB->ByteCount = cpu_to_le16(byte_count);
1105 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1106 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1107 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001108 cFYI(1, "Posix create returned %d", rc);
Steve French2dd29d32007-04-23 22:07:35 +00001109 goto psx_create_err;
1110 }
1111
Joe Perchesb6b38f72010-04-21 03:50:45 +00001112 cFYI(1, "copying inode info");
Steve French2dd29d32007-04-23 22:07:35 +00001113 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1114
Jeff Layton820a8032011-05-04 08:05:26 -04001115 if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) {
Steve French2dd29d32007-04-23 22:07:35 +00001116 rc = -EIO; /* bad smb */
1117 goto psx_create_err;
1118 }
1119
1120 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001121 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001122 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001123
Steve French2dd29d32007-04-23 22:07:35 +00001124 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001125 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001126 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1127 /* Let caller know file was created so we can set the mode. */
1128 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001129 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001130 *pOplock |= CIFS_CREATE_ACTION;
1131 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001132 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1133 pRetData->Type = cpu_to_le32(-1); /* unknown */
Joe Perchesb6b38f72010-04-21 03:50:45 +00001134 cFYI(DBG2, "unknown type");
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001135 } else {
Jeff Layton820a8032011-05-04 08:05:26 -04001136 if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001137 + sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001138 cERROR(1, "Open response data too small");
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001139 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001140 goto psx_create_err;
1141 }
Steve French50c2f752007-07-13 00:33:32 +00001142 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001143 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001144 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001145 }
Steve French2dd29d32007-04-23 22:07:35 +00001146
1147psx_create_err:
1148 cifs_buf_release(pSMB);
1149
Steve French65bc98b2009-07-10 15:27:25 +00001150 if (posix_flags & SMB_O_DIRECTORY)
1151 cifs_stats_inc(&tcon->num_posixmkdirs);
1152 else
1153 cifs_stats_inc(&tcon->num_posixopens);
Steve French2dd29d32007-04-23 22:07:35 +00001154
1155 if (rc == -EAGAIN)
1156 goto PsxCreat;
1157
Steve French50c2f752007-07-13 00:33:32 +00001158 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001159}
1160
Steve Frencha9d02ad2005-08-24 23:06:05 -07001161static __u16 convert_disposition(int disposition)
1162{
1163 __u16 ofun = 0;
1164
1165 switch (disposition) {
1166 case FILE_SUPERSEDE:
1167 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1168 break;
1169 case FILE_OPEN:
1170 ofun = SMBOPEN_OAPPEND;
1171 break;
1172 case FILE_CREATE:
1173 ofun = SMBOPEN_OCREATE;
1174 break;
1175 case FILE_OPEN_IF:
1176 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1177 break;
1178 case FILE_OVERWRITE:
1179 ofun = SMBOPEN_OTRUNC;
1180 break;
1181 case FILE_OVERWRITE_IF:
1182 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1183 break;
1184 default:
Joe Perchesb6b38f72010-04-21 03:50:45 +00001185 cFYI(1, "unknown disposition %d", disposition);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001186 ofun = SMBOPEN_OAPPEND; /* regular open */
1187 }
1188 return ofun;
1189}
1190
Jeff Layton35fc37d2008-05-14 10:22:03 -07001191static int
1192access_flags_to_smbopen_mode(const int access_flags)
1193{
1194 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1195
1196 if (masked_flags == GENERIC_READ)
1197 return SMBOPEN_READ;
1198 else if (masked_flags == GENERIC_WRITE)
1199 return SMBOPEN_WRITE;
1200
1201 /* just go for read/write */
1202 return SMBOPEN_READWRITE;
1203}
1204
Steve Frencha9d02ad2005-08-24 23:06:05 -07001205int
Steve French96daf2b2011-05-27 04:34:02 +00001206SMBLegacyOpen(const int xid, struct cifs_tcon *tcon,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001207 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001208 const int access_flags, const int create_options, __u16 *netfid,
1209 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001210 const struct nls_table *nls_codepage, int remap)
1211{
1212 int rc = -EACCES;
1213 OPENX_REQ *pSMB = NULL;
1214 OPENX_RSP *pSMBr = NULL;
1215 int bytes_returned;
1216 int name_len;
1217 __u16 count;
1218
1219OldOpenRetry:
1220 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1221 (void **) &pSMBr);
1222 if (rc)
1223 return rc;
1224
1225 pSMB->AndXCommand = 0xFF; /* none */
1226
1227 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1228 count = 1; /* account for one byte pad to word boundary */
1229 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001230 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1231 fileName, PATH_MAX, nls_codepage, remap);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001232 name_len++; /* trailing null */
1233 name_len *= 2;
1234 } else { /* BB improve check for buffer overruns BB */
1235 count = 0; /* no pad */
1236 name_len = strnlen(fileName, PATH_MAX);
1237 name_len++; /* trailing null */
1238 strncpy(pSMB->fileName, fileName, name_len);
1239 }
1240 if (*pOplock & REQ_OPLOCK)
1241 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001242 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001243 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001244
Steve Frencha9d02ad2005-08-24 23:06:05 -07001245 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001246 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001247 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1248 /* set file as system file if special file such
1249 as fifo and server expecting SFU style and
1250 no Unix extensions */
1251
Steve French790fe572007-07-07 19:25:05 +00001252 if (create_options & CREATE_OPTION_SPECIAL)
1253 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001254 else /* BB FIXME BB */
1255 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001256
Jeff Layton67750fb2008-05-09 22:28:02 +00001257 if (create_options & CREATE_OPTION_READONLY)
1258 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001259
1260 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001261/* pSMB->CreateOptions = cpu_to_le32(create_options &
1262 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001263 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001264
1265 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001266 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001267 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001268 inc_rfc1001_len(pSMB, count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001269
1270 pSMB->ByteCount = cpu_to_le16(count);
1271 /* long_op set to 1 to allow for oplock break timeouts */
1272 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001273 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001274 cifs_stats_inc(&tcon->num_opens);
1275 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001276 cFYI(1, "Error in Open = %d", rc);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001277 } else {
1278 /* BB verify if wct == 15 */
1279
Steve French582d21e2008-05-13 04:54:12 +00001280/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001281
1282 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1283 /* Let caller know file was created so we can set the mode. */
1284 /* Do we care about the CreateAction in any other cases? */
1285 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001286/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001287 *pOplock |= CIFS_CREATE_ACTION; */
1288 /* BB FIXME END */
1289
Steve French790fe572007-07-07 19:25:05 +00001290 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001291 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1292 pfile_info->LastAccessTime = 0; /* BB fixme */
1293 pfile_info->LastWriteTime = 0; /* BB fixme */
1294 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001295 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001296 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001297 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001298 pfile_info->AllocationSize =
1299 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1300 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001301 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001302 pfile_info->DeletePending = 0;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001303 }
1304 }
1305
1306 cifs_buf_release(pSMB);
1307 if (rc == -EAGAIN)
1308 goto OldOpenRetry;
1309 return rc;
1310}
1311
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312int
Steve French96daf2b2011-05-27 04:34:02 +00001313CIFSSMBOpen(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001315 const int access_flags, const int create_options, __u16 *netfid,
1316 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001317 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318{
1319 int rc = -EACCES;
1320 OPEN_REQ *pSMB = NULL;
1321 OPEN_RSP *pSMBr = NULL;
1322 int bytes_returned;
1323 int name_len;
1324 __u16 count;
1325
1326openRetry:
1327 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1328 (void **) &pSMBr);
1329 if (rc)
1330 return rc;
1331
1332 pSMB->AndXCommand = 0xFF; /* none */
1333
1334 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1335 count = 1; /* account for one byte pad to word boundary */
1336 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001337 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1338 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339 name_len++; /* trailing null */
1340 name_len *= 2;
1341 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001342 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343 count = 0; /* no pad */
1344 name_len = strnlen(fileName, PATH_MAX);
1345 name_len++; /* trailing null */
1346 pSMB->NameLength = cpu_to_le16(name_len);
1347 strncpy(pSMB->fileName, fileName, name_len);
1348 }
1349 if (*pOplock & REQ_OPLOCK)
1350 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001351 else if (*pOplock & REQ_BATCHOPLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1354 pSMB->AllocationSize = 0;
Steve Frencheda3c022005-07-21 15:20:28 -07001355 /* set file as system file if special file such
1356 as fifo and server expecting SFU style and
1357 no Unix extensions */
Steve French790fe572007-07-07 19:25:05 +00001358 if (create_options & CREATE_OPTION_SPECIAL)
Steve Frencheda3c022005-07-21 15:20:28 -07001359 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1360 else
1361 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Jeff Layton67750fb2008-05-09 22:28:02 +00001362
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363 /* XP does not handle ATTR_POSIX_SEMANTICS */
1364 /* but it helps speed up case sensitive checks for other
1365 servers such as Samba */
1366 if (tcon->ses->capabilities & CAP_UNIX)
1367 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1368
Jeff Layton67750fb2008-05-09 22:28:02 +00001369 if (create_options & CREATE_OPTION_READONLY)
1370 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1371
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1373 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c022005-07-21 15:20:28 -07001374 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001375 /* BB Expirement with various impersonation levels and verify */
1376 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377 pSMB->SecurityFlags =
1378 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1379
1380 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001381 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382
1383 pSMB->ByteCount = cpu_to_le16(count);
1384 /* long_op set to 1 to allow for oplock break timeouts */
1385 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001386 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001387 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001388 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001389 cFYI(1, "Error in Open = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390 } else {
Steve French09d1db52005-04-28 22:41:08 -07001391 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1393 /* Let caller know file was created so we can set the mode. */
1394 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001395 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve French50c2f752007-07-13 00:33:32 +00001396 *pOplock |= CIFS_CREATE_ACTION;
Steve French790fe572007-07-07 19:25:05 +00001397 if (pfile_info) {
Steve French61e74802008-12-03 00:57:54 +00001398 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1399 36 /* CreationTime to Attributes */);
1400 /* the file_info buf is endian converted by caller */
1401 pfile_info->AllocationSize = pSMBr->AllocationSize;
1402 pfile_info->EndOfFile = pSMBr->EndOfFile;
1403 pfile_info->NumberOfLinks = cpu_to_le32(1);
1404 pfile_info->DeletePending = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001407
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408 cifs_buf_release(pSMB);
1409 if (rc == -EAGAIN)
1410 goto openRetry;
1411 return rc;
1412}
1413
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001414struct cifs_readdata *
1415cifs_readdata_alloc(unsigned int nr_pages)
1416{
1417 struct cifs_readdata *rdata;
1418
1419 /* readdata + 1 kvec for each page */
1420 rdata = kzalloc(sizeof(*rdata) +
1421 sizeof(struct kvec) * nr_pages, GFP_KERNEL);
1422 if (rdata != NULL) {
1423 INIT_WORK(&rdata->work, cifs_readv_complete);
1424 INIT_LIST_HEAD(&rdata->pages);
1425 }
1426 return rdata;
1427}
1428
1429void
1430cifs_readdata_free(struct cifs_readdata *rdata)
1431{
1432 cifsFileInfo_put(rdata->cfile);
1433 kfree(rdata);
1434}
1435
1436/*
1437 * Discard any remaining data in the current SMB. To do this, we borrow the
1438 * current bigbuf.
1439 */
1440static int
1441cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1442{
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001443 unsigned int rfclen = get_rfc1002_length(server->smallbuf);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001444 int remaining = rfclen + 4 - server->total_read;
1445 struct cifs_readdata *rdata = mid->callback_data;
1446
1447 while (remaining > 0) {
1448 int length;
1449
1450 length = cifs_read_from_socket(server, server->bigbuf,
1451 min_t(unsigned int, remaining,
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001452 CIFSMaxBufSize + max_header_size()));
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001453 if (length < 0)
1454 return length;
1455 server->total_read += length;
1456 remaining -= length;
1457 }
1458
1459 dequeue_mid(mid, rdata->result);
1460 return 0;
1461}
1462
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001463static inline size_t
1464read_rsp_size(void)
1465{
1466 return sizeof(READ_RSP);
1467}
1468
1469static inline unsigned int
1470read_data_offset(char *buf)
1471{
1472 READ_RSP *rsp = (READ_RSP *)buf;
1473 return le16_to_cpu(rsp->DataOffset);
1474}
1475
1476static inline unsigned int
1477read_data_length(char *buf)
1478{
1479 READ_RSP *rsp = (READ_RSP *)buf;
1480 return (le16_to_cpu(rsp->DataLengthHigh) << 16) +
1481 le16_to_cpu(rsp->DataLength);
1482}
1483
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001484static int
1485cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1486{
1487 int length, len;
1488 unsigned int data_offset, remaining, data_len;
1489 struct cifs_readdata *rdata = mid->callback_data;
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001490 char *buf = server->smallbuf;
1491 unsigned int buflen = get_rfc1002_length(buf) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001492 u64 eof;
1493 pgoff_t eof_index;
1494 struct page *page, *tpage;
1495
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001496 cFYI(1, "%s: mid=%llu offset=%llu bytes=%u", __func__,
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001497 mid->mid, rdata->offset, rdata->bytes);
1498
1499 /*
1500 * read the rest of READ_RSP header (sans Data array), or whatever we
1501 * can if there's not enough data. At this point, we've read down to
1502 * the Mid.
1503 */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001504 len = min_t(unsigned int, buflen, read_rsp_size()) - header_size() + 1;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001505
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001506 rdata->iov[0].iov_base = buf + header_size() - 1;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001507 rdata->iov[0].iov_len = len;
1508
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 /* Was the SMB read successful? */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001515 rdata->result = map_smb_to_linux_error(buf, false);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001516 if (rdata->result != 0) {
1517 cFYI(1, "%s: server returned error %d", __func__,
1518 rdata->result);
1519 return cifs_readv_discard(server, mid);
1520 }
1521
1522 /* Is there enough to get to the rest of the READ_RSP header? */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001523 if (server->total_read < read_rsp_size()) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001524 cFYI(1, "%s: server returned short header. got=%u expected=%zu",
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001525 __func__, server->total_read, read_rsp_size());
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001526 rdata->result = -EIO;
1527 return cifs_readv_discard(server, mid);
1528 }
1529
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001530 data_offset = read_data_offset(buf) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001531 if (data_offset < server->total_read) {
1532 /*
1533 * win2k8 sometimes sends an offset of 0 when the read
1534 * is beyond the EOF. Treat it as if the data starts just after
1535 * the header.
1536 */
1537 cFYI(1, "%s: data offset (%u) inside read response header",
1538 __func__, data_offset);
1539 data_offset = server->total_read;
1540 } else if (data_offset > MAX_CIFS_SMALL_BUFFER_SIZE) {
1541 /* data_offset is beyond the end of smallbuf */
1542 cFYI(1, "%s: data offset (%u) beyond end of smallbuf",
1543 __func__, data_offset);
1544 rdata->result = -EIO;
1545 return cifs_readv_discard(server, mid);
1546 }
1547
1548 cFYI(1, "%s: total_read=%u data_offset=%u", __func__,
1549 server->total_read, data_offset);
1550
1551 len = data_offset - server->total_read;
1552 if (len > 0) {
1553 /* read any junk before data into the rest of smallbuf */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001554 rdata->iov[0].iov_base = buf + server->total_read;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001555 rdata->iov[0].iov_len = len;
1556 length = cifs_readv_from_socket(server, rdata->iov, 1, len);
1557 if (length < 0)
1558 return length;
1559 server->total_read += length;
1560 }
1561
1562 /* set up first iov for signature check */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001563 rdata->iov[0].iov_base = buf;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001564 rdata->iov[0].iov_len = server->total_read;
1565 cFYI(1, "0: iov_base=%p iov_len=%zu",
1566 rdata->iov[0].iov_base, rdata->iov[0].iov_len);
1567
1568 /* how much data is in the response? */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001569 data_len = read_data_length(buf);
1570 if (data_offset + data_len > buflen) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001571 /* data_len is corrupt -- discard frame */
1572 rdata->result = -EIO;
1573 return cifs_readv_discard(server, mid);
1574 }
1575
1576 /* marshal up the page array */
1577 len = 0;
1578 remaining = data_len;
1579 rdata->nr_iov = 1;
1580
1581 /* determine the eof that the server (probably) has */
1582 eof = CIFS_I(rdata->mapping->host)->server_eof;
1583 eof_index = eof ? (eof - 1) >> PAGE_CACHE_SHIFT : 0;
1584 cFYI(1, "eof=%llu eof_index=%lu", eof, eof_index);
1585
Jeff Layton5d0c7b42012-07-11 09:09:36 -04001586 cifs_kmap_lock();
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001587 list_for_each_entry_safe(page, tpage, &rdata->pages, lru) {
1588 if (remaining >= PAGE_CACHE_SIZE) {
1589 /* enough data to fill the page */
1590 rdata->iov[rdata->nr_iov].iov_base = kmap(page);
1591 rdata->iov[rdata->nr_iov].iov_len = PAGE_CACHE_SIZE;
1592 cFYI(1, "%u: idx=%lu iov_base=%p iov_len=%zu",
1593 rdata->nr_iov, page->index,
1594 rdata->iov[rdata->nr_iov].iov_base,
1595 rdata->iov[rdata->nr_iov].iov_len);
1596 ++rdata->nr_iov;
1597 len += PAGE_CACHE_SIZE;
1598 remaining -= PAGE_CACHE_SIZE;
1599 } else if (remaining > 0) {
1600 /* enough for partial page, fill and zero the rest */
1601 rdata->iov[rdata->nr_iov].iov_base = kmap(page);
1602 rdata->iov[rdata->nr_iov].iov_len = remaining;
1603 cFYI(1, "%u: idx=%lu iov_base=%p iov_len=%zu",
1604 rdata->nr_iov, page->index,
1605 rdata->iov[rdata->nr_iov].iov_base,
1606 rdata->iov[rdata->nr_iov].iov_len);
1607 memset(rdata->iov[rdata->nr_iov].iov_base + remaining,
1608 '\0', PAGE_CACHE_SIZE - remaining);
1609 ++rdata->nr_iov;
1610 len += remaining;
1611 remaining = 0;
1612 } else if (page->index > eof_index) {
1613 /*
1614 * The VFS will not try to do readahead past the
1615 * i_size, but it's possible that we have outstanding
1616 * writes with gaps in the middle and the i_size hasn't
1617 * caught up yet. Populate those with zeroed out pages
1618 * to prevent the VFS from repeatedly attempting to
1619 * fill them until the writes are flushed.
1620 */
1621 zero_user(page, 0, PAGE_CACHE_SIZE);
1622 list_del(&page->lru);
1623 lru_cache_add_file(page);
1624 flush_dcache_page(page);
1625 SetPageUptodate(page);
1626 unlock_page(page);
1627 page_cache_release(page);
1628 } else {
1629 /* no need to hold page hostage */
1630 list_del(&page->lru);
1631 lru_cache_add_file(page);
1632 unlock_page(page);
1633 page_cache_release(page);
1634 }
1635 }
Jeff Layton5d0c7b42012-07-11 09:09:36 -04001636 cifs_kmap_unlock();
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001637
1638 /* issue the read if we have any iovecs left to fill */
1639 if (rdata->nr_iov > 1) {
1640 length = cifs_readv_from_socket(server, &rdata->iov[1],
1641 rdata->nr_iov - 1, len);
1642 if (length < 0)
1643 return length;
1644 server->total_read += length;
1645 } else {
1646 length = 0;
1647 }
1648
1649 rdata->bytes = length;
1650
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001651 cFYI(1, "total_read=%u buflen=%u remaining=%u", server->total_read,
1652 buflen, remaining);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001653
1654 /* discard anything left over */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001655 if (server->total_read < buflen)
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001656 return cifs_readv_discard(server, mid);
1657
1658 dequeue_mid(mid, false);
1659 return length;
1660}
1661
1662static void
1663cifs_readv_complete(struct work_struct *work)
1664{
1665 struct cifs_readdata *rdata = container_of(work,
1666 struct cifs_readdata, work);
1667 struct page *page, *tpage;
1668
1669 list_for_each_entry_safe(page, tpage, &rdata->pages, lru) {
1670 list_del(&page->lru);
1671 lru_cache_add_file(page);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001672
1673 if (rdata->result == 0) {
Pavel Shilovskya2d6b6c2011-10-21 10:14:04 +04001674 kunmap(page);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001675 flush_dcache_page(page);
1676 SetPageUptodate(page);
1677 }
1678
1679 unlock_page(page);
1680
1681 if (rdata->result == 0)
1682 cifs_readpage_to_fscache(rdata->mapping->host, page);
1683
1684 page_cache_release(page);
1685 }
1686 cifs_readdata_free(rdata);
1687}
1688
1689static void
1690cifs_readv_callback(struct mid_q_entry *mid)
1691{
1692 struct cifs_readdata *rdata = mid->callback_data;
1693 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1694 struct TCP_Server_Info *server = tcon->ses->server;
1695
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001696 cFYI(1, "%s: mid=%llu state=%d result=%d bytes=%u", __func__,
1697 mid->mid, mid->mid_state, rdata->result, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001698
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001699 switch (mid->mid_state) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001700 case MID_RESPONSE_RECEIVED:
1701 /* result already set, check signature */
1702 if (server->sec_mode &
1703 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
1704 if (cifs_verify_signature(rdata->iov, rdata->nr_iov,
1705 server, mid->sequence_number + 1))
1706 cERROR(1, "Unexpected SMB signature");
1707 }
1708 /* FIXME: should this be counted toward the initiating task? */
1709 task_io_account_read(rdata->bytes);
1710 cifs_stats_bytes_read(tcon, rdata->bytes);
1711 break;
1712 case MID_REQUEST_SUBMITTED:
1713 case MID_RETRY_NEEDED:
1714 rdata->result = -EAGAIN;
1715 break;
1716 default:
1717 rdata->result = -EIO;
1718 }
1719
Jeff Laytonda472fc2012-03-23 14:40:53 -04001720 queue_work(cifsiod_wq, &rdata->work);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001721 DeleteMidQEntry(mid);
Pavel Shilovsky2d86dbc2012-02-06 15:59:18 +04001722 cifs_add_credits(server, 1);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001723}
1724
1725/* cifs_async_readv - send an async write, and set up mid to handle result */
1726int
1727cifs_async_readv(struct cifs_readdata *rdata)
1728{
1729 int rc;
1730 READ_REQ *smb = NULL;
1731 int wct;
1732 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1733
1734 cFYI(1, "%s: offset=%llu bytes=%u", __func__,
1735 rdata->offset, rdata->bytes);
1736
1737 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1738 wct = 12;
1739 else {
1740 wct = 10; /* old style read */
1741 if ((rdata->offset >> 32) > 0) {
1742 /* can not handle this big offset for old */
1743 return -EIO;
1744 }
1745 }
1746
1747 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **)&smb);
1748 if (rc)
1749 return rc;
1750
1751 smb->hdr.Pid = cpu_to_le16((__u16)rdata->pid);
1752 smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16));
1753
1754 smb->AndXCommand = 0xFF; /* none */
1755 smb->Fid = rdata->cfile->netfid;
1756 smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF);
1757 if (wct == 12)
1758 smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32);
1759 smb->Remaining = 0;
1760 smb->MaxCount = cpu_to_le16(rdata->bytes & 0xFFFF);
1761 smb->MaxCountHigh = cpu_to_le32(rdata->bytes >> 16);
1762 if (wct == 12)
1763 smb->ByteCount = 0;
1764 else {
1765 /* old style read */
1766 struct smb_com_readx_req *smbr =
1767 (struct smb_com_readx_req *)smb;
1768 smbr->ByteCount = 0;
1769 }
1770
1771 /* 4 for RFC1001 length + 1 for BCC */
1772 rdata->iov[0].iov_base = smb;
1773 rdata->iov[0].iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
1774
1775 rc = cifs_call_async(tcon->ses->server, rdata->iov, 1,
1776 cifs_readv_receive, cifs_readv_callback,
1777 rdata, false);
1778
1779 if (rc == 0)
1780 cifs_stats_inc(&tcon->num_reads);
1781
1782 cifs_small_buf_release(smb);
1783 return rc;
1784}
1785
Linus Torvalds1da177e2005-04-16 15:20:36 -07001786int
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001787CIFSSMBRead(const int xid, struct cifs_io_parms *io_parms, unsigned int *nbytes,
Steve French50c2f752007-07-13 00:33:32 +00001788 char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001789{
1790 int rc = -EACCES;
1791 READ_REQ *pSMB = NULL;
1792 READ_RSP *pSMBr = NULL;
1793 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001794 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001795 int resp_buf_type = 0;
1796 struct kvec iov[1];
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001797 __u32 pid = io_parms->pid;
1798 __u16 netfid = io_parms->netfid;
1799 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001800 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001801 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802
Joe Perchesb6b38f72010-04-21 03:50:45 +00001803 cFYI(1, "Reading %d bytes on fid %d", count, netfid);
Steve French790fe572007-07-07 19:25:05 +00001804 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001805 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001806 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001807 wct = 10; /* old style read */
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001808 if ((offset >> 32) > 0) {
Steve French4c3130e2008-12-09 00:28:16 +00001809 /* can not handle this big offset for old */
1810 return -EIO;
1811 }
1812 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001813
1814 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001815 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001816 if (rc)
1817 return rc;
1818
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001819 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1820 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1821
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822 /* tcon and ses pointer are checked in smb_init */
1823 if (tcon->ses->server == NULL)
1824 return -ECONNABORTED;
1825
Steve Frenchec637e32005-12-12 20:53:18 -08001826 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001827 pSMB->Fid = netfid;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001828 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001829 if (wct == 12)
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001830 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001831
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832 pSMB->Remaining = 0;
1833 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1834 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001835 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001836 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1837 else {
1838 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001839 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001840 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001841 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001842 }
Steve Frenchec637e32005-12-12 20:53:18 -08001843
1844 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001845 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve Frencha761ac52007-10-18 21:45:27 +00001846 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Jeff Layton77499812011-01-11 07:24:23 -05001847 &resp_buf_type, CIFS_LOG_ERROR);
Steve Frencha4544342005-08-24 13:59:35 -07001848 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001849 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001851 cERROR(1, "Send error in read = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852 } else {
1853 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1854 data_length = data_length << 16;
1855 data_length += le16_to_cpu(pSMBr->DataLength);
1856 *nbytes = data_length;
1857
1858 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001859 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860 || (data_length > count)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001861 cFYI(1, "bad length %d for count %d",
1862 data_length, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863 rc = -EIO;
1864 *nbytes = 0;
1865 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001866 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001867 le16_to_cpu(pSMBr->DataOffset);
1868/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001869 cERROR(1, "Faulting on read rc = %d",rc);
Steve French50c2f752007-07-13 00:33:32 +00001870 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001871 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001872 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001873 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874 }
1875 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876
Steve French4b8f9302006-02-26 16:41:18 +00001877/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001878 if (*buf) {
1879 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001880 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001881 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001882 cifs_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001883 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001884 /* return buffer to caller to free */
1885 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001886 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001887 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001888 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001889 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001890 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001891
1892 /* 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 return rc;
1895}
1896
Steve Frenchec637e32005-12-12 20:53:18 -08001897
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898int
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001899CIFSSMBWrite(const int xid, struct cifs_io_parms *io_parms,
1900 unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001901 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001902{
1903 int rc = -EACCES;
1904 WRITE_REQ *pSMB = NULL;
1905 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001906 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001907 __u32 bytes_sent;
1908 __u16 byte_count;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001909 __u32 pid = io_parms->pid;
1910 __u16 netfid = io_parms->netfid;
1911 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001912 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001913 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001914
Steve Frencha24e2d72010-04-03 17:20:21 +00001915 *nbytes = 0;
1916
Joe Perchesb6b38f72010-04-21 03:50:45 +00001917 /* cFYI(1, "write at %lld %d bytes", offset, count);*/
Steve French790fe572007-07-07 19:25:05 +00001918 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001919 return -ECONNABORTED;
1920
Steve French790fe572007-07-07 19:25:05 +00001921 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001922 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001923 else {
Steve French1c955182005-08-30 20:58:07 -07001924 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001925 if ((offset >> 32) > 0) {
1926 /* can not handle big offset for old srv */
1927 return -EIO;
1928 }
1929 }
Steve French1c955182005-08-30 20:58:07 -07001930
1931 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932 (void **) &pSMBr);
1933 if (rc)
1934 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001935
1936 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1937 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1938
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939 /* tcon and ses pointer are checked in smb_init */
1940 if (tcon->ses->server == NULL)
1941 return -ECONNABORTED;
1942
1943 pSMB->AndXCommand = 0xFF; /* none */
1944 pSMB->Fid = netfid;
1945 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001946 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001947 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001948
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949 pSMB->Reserved = 0xFFFFFFFF;
1950 pSMB->WriteMode = 0;
1951 pSMB->Remaining = 0;
1952
Steve French50c2f752007-07-13 00:33:32 +00001953 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001954 can send more if LARGE_WRITE_X capability returned by the server and if
1955 our buffer is big enough or if we convert to iovecs on socket writes
1956 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001957 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1959 } else {
1960 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1961 & ~0xFF;
1962 }
1963
1964 if (bytes_sent > count)
1965 bytes_sent = count;
1966 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001967 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001968 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001969 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001970 else if (ubuf) {
1971 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001972 cifs_buf_release(pSMB);
1973 return -EFAULT;
1974 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001975 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976 /* No buffer */
1977 cifs_buf_release(pSMB);
1978 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001979 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001980 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001981 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001982 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001983 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001984
Linus Torvalds1da177e2005-04-16 15:20:36 -07001985 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1986 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001987 inc_rfc1001_len(pSMB, byte_count);
Steve French1c955182005-08-30 20:58:07 -07001988
Steve French790fe572007-07-07 19:25:05 +00001989 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001990 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001991 else { /* old style write has byte count 4 bytes earlier
1992 so 4 bytes pad */
1993 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001994 (struct smb_com_writex_req *)pSMB;
1995 pSMBW->ByteCount = cpu_to_le16(byte_count);
1996 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997
1998 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1999 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07002000 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00002002 cFYI(1, "Send error in write = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002003 } else {
2004 *nbytes = le16_to_cpu(pSMBr->CountHigh);
2005 *nbytes = (*nbytes) << 16;
2006 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05302007
2008 /*
2009 * Mask off high 16 bits when bytes written as returned by the
2010 * server is greater than bytes requested by the client. Some
2011 * OS/2 servers are known to set incorrect CountHigh values.
2012 */
2013 if (*nbytes > count)
2014 *nbytes &= 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002015 }
2016
2017 cifs_buf_release(pSMB);
2018
Steve French50c2f752007-07-13 00:33:32 +00002019 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002020 since file handle passed in no longer valid */
2021
2022 return rc;
2023}
2024
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002025void
2026cifs_writedata_release(struct kref *refcount)
2027{
2028 struct cifs_writedata *wdata = container_of(refcount,
2029 struct cifs_writedata, refcount);
2030
2031 if (wdata->cfile)
2032 cifsFileInfo_put(wdata->cfile);
2033
2034 kfree(wdata);
2035}
2036
2037/*
2038 * Write failed with a retryable error. Resend the write request. It's also
2039 * possible that the page was redirtied so re-clean the page.
2040 */
2041static void
2042cifs_writev_requeue(struct cifs_writedata *wdata)
2043{
2044 int i, rc;
2045 struct inode *inode = wdata->cfile->dentry->d_inode;
2046
2047 for (i = 0; i < wdata->nr_pages; i++) {
2048 lock_page(wdata->pages[i]);
2049 clear_page_dirty_for_io(wdata->pages[i]);
2050 }
2051
2052 do {
2053 rc = cifs_async_writev(wdata);
2054 } while (rc == -EAGAIN);
2055
2056 for (i = 0; i < wdata->nr_pages; i++) {
2057 if (rc != 0)
2058 SetPageError(wdata->pages[i]);
2059 unlock_page(wdata->pages[i]);
2060 }
2061
2062 mapping_set_error(inode->i_mapping, rc);
2063 kref_put(&wdata->refcount, cifs_writedata_release);
2064}
2065
Jeff Laytonc2e87642012-03-23 14:40:55 -04002066void
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002067cifs_writev_complete(struct work_struct *work)
2068{
2069 struct cifs_writedata *wdata = container_of(work,
2070 struct cifs_writedata, work);
2071 struct inode *inode = wdata->cfile->dentry->d_inode;
2072 int i = 0;
2073
2074 if (wdata->result == 0) {
Jeff Layton597b0272012-03-23 14:40:56 -04002075 spin_lock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002076 cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
Jeff Layton597b0272012-03-23 14:40:56 -04002077 spin_unlock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002078 cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
2079 wdata->bytes);
2080 } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
2081 return cifs_writev_requeue(wdata);
2082
2083 for (i = 0; i < wdata->nr_pages; i++) {
2084 struct page *page = wdata->pages[i];
2085 if (wdata->result == -EAGAIN)
2086 __set_page_dirty_nobuffers(page);
2087 else if (wdata->result < 0)
2088 SetPageError(page);
2089 end_page_writeback(page);
2090 page_cache_release(page);
2091 }
2092 if (wdata->result != -EAGAIN)
2093 mapping_set_error(inode->i_mapping, wdata->result);
2094 kref_put(&wdata->refcount, cifs_writedata_release);
2095}
2096
2097struct cifs_writedata *
Jeff Laytonc2e87642012-03-23 14:40:55 -04002098cifs_writedata_alloc(unsigned int nr_pages, work_func_t complete)
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002099{
2100 struct cifs_writedata *wdata;
2101
2102 /* this would overflow */
2103 if (nr_pages == 0) {
2104 cERROR(1, "%s: called with nr_pages == 0!", __func__);
2105 return NULL;
2106 }
2107
2108 /* writedata + number of page pointers */
2109 wdata = kzalloc(sizeof(*wdata) +
2110 sizeof(struct page *) * (nr_pages - 1), GFP_NOFS);
2111 if (wdata != NULL) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002112 kref_init(&wdata->refcount);
Jeff Laytonda82f7e2012-03-23 14:40:56 -04002113 INIT_LIST_HEAD(&wdata->list);
2114 init_completion(&wdata->done);
2115 INIT_WORK(&wdata->work, complete);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002116 }
2117 return wdata;
2118}
2119
2120/*
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04002121 * Check the mid_state and signature on received buffer (if any), and queue the
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002122 * workqueue completion task.
2123 */
2124static void
2125cifs_writev_callback(struct mid_q_entry *mid)
2126{
2127 struct cifs_writedata *wdata = mid->callback_data;
Steve French96daf2b2011-05-27 04:34:02 +00002128 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002129 unsigned int written;
2130 WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
2131
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04002132 switch (mid->mid_state) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002133 case MID_RESPONSE_RECEIVED:
2134 wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
2135 if (wdata->result != 0)
2136 break;
2137
2138 written = le16_to_cpu(smb->CountHigh);
2139 written <<= 16;
2140 written += le16_to_cpu(smb->Count);
2141 /*
2142 * Mask off high 16 bits when bytes written as returned
2143 * by the server is greater than bytes requested by the
2144 * client. OS/2 servers are known to set incorrect
2145 * CountHigh values.
2146 */
2147 if (written > wdata->bytes)
2148 written &= 0xFFFF;
2149
2150 if (written < wdata->bytes)
2151 wdata->result = -ENOSPC;
2152 else
2153 wdata->bytes = written;
2154 break;
2155 case MID_REQUEST_SUBMITTED:
2156 case MID_RETRY_NEEDED:
2157 wdata->result = -EAGAIN;
2158 break;
2159 default:
2160 wdata->result = -EIO;
2161 break;
2162 }
2163
Jeff Laytonda472fc2012-03-23 14:40:53 -04002164 queue_work(cifsiod_wq, &wdata->work);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002165 DeleteMidQEntry(mid);
Pavel Shilovsky2d86dbc2012-02-06 15:59:18 +04002166 cifs_add_credits(tcon->ses->server, 1);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002167}
2168
2169/* cifs_async_writev - send an async write, and set up mid to handle result */
2170int
2171cifs_async_writev(struct cifs_writedata *wdata)
2172{
2173 int i, rc = -EACCES;
2174 WRITE_REQ *smb = NULL;
2175 int wct;
Steve French96daf2b2011-05-27 04:34:02 +00002176 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002177 struct kvec *iov = NULL;
2178
2179 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
2180 wct = 14;
2181 } else {
2182 wct = 12;
2183 if (wdata->offset >> 32 > 0) {
2184 /* can not handle big offset for old srv */
2185 return -EIO;
2186 }
2187 }
2188
2189 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
2190 if (rc)
2191 goto async_writev_out;
2192
2193 /* 1 iov per page + 1 for header */
2194 iov = kzalloc((wdata->nr_pages + 1) * sizeof(*iov), GFP_NOFS);
2195 if (iov == NULL) {
2196 rc = -ENOMEM;
2197 goto async_writev_out;
2198 }
2199
Jeff Laytonfe5f5d22012-03-23 14:40:55 -04002200 smb->hdr.Pid = cpu_to_le16((__u16)wdata->pid);
2201 smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16));
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002202
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002203 smb->AndXCommand = 0xFF; /* none */
2204 smb->Fid = wdata->cfile->netfid;
2205 smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
2206 if (wct == 14)
2207 smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
2208 smb->Reserved = 0xFFFFFFFF;
2209 smb->WriteMode = 0;
2210 smb->Remaining = 0;
2211
2212 smb->DataOffset =
2213 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
2214
2215 /* 4 for RFC1001 length + 1 for BCC */
2216 iov[0].iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4 + 1;
2217 iov[0].iov_base = smb;
2218
Jeff Laytone9492872012-03-23 14:40:56 -04002219 /*
2220 * This function should marshal up the page array into the kvec
2221 * array, reserving [0] for the header. It should kmap the pages
2222 * and set the iov_len properly for each one. It may also set
2223 * wdata->bytes too.
2224 */
Jeff Layton5d0c7b42012-07-11 09:09:36 -04002225 cifs_kmap_lock();
Jeff Laytone9492872012-03-23 14:40:56 -04002226 wdata->marshal_iov(iov, wdata);
Jeff Layton5d0c7b42012-07-11 09:09:36 -04002227 cifs_kmap_unlock();
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002228
2229 cFYI(1, "async write at %llu %u bytes", wdata->offset, wdata->bytes);
2230
2231 smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
2232 smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16);
2233
2234 if (wct == 14) {
2235 inc_rfc1001_len(&smb->hdr, wdata->bytes + 1);
2236 put_bcc(wdata->bytes + 1, &smb->hdr);
2237 } else {
2238 /* wct == 12 */
2239 struct smb_com_writex_req *smbw =
2240 (struct smb_com_writex_req *)smb;
2241 inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
2242 put_bcc(wdata->bytes + 5, &smbw->hdr);
2243 iov[0].iov_len += 4; /* pad bigger by four bytes */
2244 }
2245
2246 kref_get(&wdata->refcount);
2247 rc = cifs_call_async(tcon->ses->server, iov, wdata->nr_pages + 1,
Jeff Layton44d22d82011-10-19 15:29:49 -04002248 NULL, cifs_writev_callback, wdata, false);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002249
2250 if (rc == 0)
2251 cifs_stats_inc(&tcon->num_writes);
2252 else
2253 kref_put(&wdata->refcount, cifs_writedata_release);
2254
2255 /* send is done, unmap pages */
2256 for (i = 0; i < wdata->nr_pages; i++)
2257 kunmap(wdata->pages[i]);
2258
2259async_writev_out:
2260 cifs_small_buf_release(smb);
2261 kfree(iov);
2262 return rc;
2263}
2264
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002265int
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002266CIFSSMBWrite2(const int xid, struct cifs_io_parms *io_parms,
2267 unsigned int *nbytes, struct kvec *iov, int n_vec,
2268 const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002269{
2270 int rc = -EACCES;
2271 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08002272 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002273 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08002274 int resp_buf_type = 0;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002275 __u32 pid = io_parms->pid;
2276 __u16 netfid = io_parms->netfid;
2277 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00002278 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002279 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002280
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04002281 *nbytes = 0;
2282
Joe Perchesb6b38f72010-04-21 03:50:45 +00002283 cFYI(1, "write2 at %lld %d bytes", (long long)offset, count);
Steve Frenchff7feac2005-11-15 16:45:16 -08002284
Steve French4c3130e2008-12-09 00:28:16 +00002285 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07002286 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00002287 } else {
Steve French8cc64c62005-10-03 13:49:43 -07002288 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00002289 if ((offset >> 32) > 0) {
2290 /* can not handle big offset for old srv */
2291 return -EIO;
2292 }
2293 }
Steve French8cc64c62005-10-03 13:49:43 -07002294 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002295 if (rc)
2296 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002297
2298 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
2299 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
2300
Linus Torvalds1da177e2005-04-16 15:20:36 -07002301 /* tcon and ses pointer are checked in smb_init */
2302 if (tcon->ses->server == NULL)
2303 return -ECONNABORTED;
2304
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002305 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002306 pSMB->Fid = netfid;
2307 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00002308 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002309 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310 pSMB->Reserved = 0xFFFFFFFF;
2311 pSMB->WriteMode = 0;
2312 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002313
Linus Torvalds1da177e2005-04-16 15:20:36 -07002314 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00002315 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002316
Steve French3e844692005-10-03 13:37:24 -07002317 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
2318 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002319 /* header + 1 byte pad */
2320 smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
Steve French790fe572007-07-07 19:25:05 +00002321 if (wct == 14)
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002322 inc_rfc1001_len(pSMB, count + 1);
Steve French8cc64c62005-10-03 13:49:43 -07002323 else /* wct == 12 */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002324 inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
Steve French790fe572007-07-07 19:25:05 +00002325 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002326 pSMB->ByteCount = cpu_to_le16(count + 1);
2327 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00002328 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07002329 (struct smb_com_writex_req *)pSMB;
2330 pSMBW->ByteCount = cpu_to_le16(count + 5);
2331 }
Steve French3e844692005-10-03 13:37:24 -07002332 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00002333 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08002334 iov[0].iov_len = smb_hdr_len + 4;
2335 else /* wct == 12 pad bigger by four bytes */
2336 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00002337
Steve French3e844692005-10-03 13:37:24 -07002338
Steve Frenchec637e32005-12-12 20:53:18 -08002339 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French133672e2007-11-13 22:41:37 +00002340 long_op);
Steve Frencha4544342005-08-24 13:59:35 -07002341 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002342 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002343 cFYI(1, "Send error Write2 = %d", rc);
Steve French790fe572007-07-07 19:25:05 +00002344 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08002345 /* presumably this can not happen, but best to be safe */
2346 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002347 } else {
Steve Frenchad7a2922008-02-07 23:25:02 +00002348 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002349 *nbytes = le16_to_cpu(pSMBr->CountHigh);
2350 *nbytes = (*nbytes) << 16;
2351 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05302352
2353 /*
2354 * Mask off high 16 bits when bytes written as returned by the
2355 * server is greater than bytes requested by the client. OS/2
2356 * servers are known to set incorrect CountHigh values.
2357 */
2358 if (*nbytes > count)
2359 *nbytes &= 0xFFFF;
Steve French50c2f752007-07-13 00:33:32 +00002360 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002361
Steve French4b8f9302006-02-26 16:41:18 +00002362/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00002363 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002364 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00002365 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002366 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002367
Steve French50c2f752007-07-13 00:33:32 +00002368 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002369 since file handle passed in no longer valid */
2370
2371 return rc;
2372}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002373
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002374int cifs_lockv(const int xid, struct cifs_tcon *tcon, const __u16 netfid,
2375 const __u8 lock_type, const __u32 num_unlock,
2376 const __u32 num_lock, LOCKING_ANDX_RANGE *buf)
2377{
2378 int rc = 0;
2379 LOCK_REQ *pSMB = NULL;
2380 struct kvec iov[2];
2381 int resp_buf_type;
2382 __u16 count;
2383
2384 cFYI(1, "cifs_lockv num lock %d num unlock %d", num_lock, num_unlock);
2385
2386 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2387 if (rc)
2388 return rc;
2389
2390 pSMB->Timeout = 0;
2391 pSMB->NumberOfLocks = cpu_to_le16(num_lock);
2392 pSMB->NumberOfUnlocks = cpu_to_le16(num_unlock);
2393 pSMB->LockType = lock_type;
2394 pSMB->AndXCommand = 0xFF; /* none */
2395 pSMB->Fid = netfid; /* netfid stays le */
2396
2397 count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2398 inc_rfc1001_len(pSMB, count);
2399 pSMB->ByteCount = cpu_to_le16(count);
2400
2401 iov[0].iov_base = (char *)pSMB;
2402 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 -
2403 (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2404 iov[1].iov_base = (char *)buf;
2405 iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2406
2407 cifs_stats_inc(&tcon->num_locks);
2408 rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP);
2409 if (rc)
2410 cFYI(1, "Send error in cifs_lockv = %d", rc);
2411
2412 return rc;
2413}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002414
Linus Torvalds1da177e2005-04-16 15:20:36 -07002415int
Steve French96daf2b2011-05-27 04:34:02 +00002416CIFSSMBLock(const int xid, struct cifs_tcon *tcon,
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002417 const __u16 smb_file_id, const __u32 netpid, const __u64 len,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002418 const __u64 offset, const __u32 numUnlock,
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002419 const __u32 numLock, const __u8 lockType,
2420 const bool waitFlag, const __u8 oplock_level)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002421{
2422 int rc = 0;
2423 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002424/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002425 int bytes_returned;
2426 int timeout = 0;
2427 __u16 count;
2428
Joe Perchesb6b38f72010-04-21 03:50:45 +00002429 cFYI(1, "CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock);
Steve French46810cb2005-04-28 22:41:09 -07002430 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2431
Linus Torvalds1da177e2005-04-16 15:20:36 -07002432 if (rc)
2433 return rc;
2434
Steve French790fe572007-07-07 19:25:05 +00002435 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Steve French133672e2007-11-13 22:41:37 +00002436 timeout = CIFS_ASYNC_OP; /* no response expected */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002437 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00002438 } else if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00002439 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002440 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
2441 } else {
2442 pSMB->Timeout = 0;
2443 }
2444
2445 pSMB->NumberOfLocks = cpu_to_le16(numLock);
2446 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
2447 pSMB->LockType = lockType;
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002448 pSMB->OplockLevel = oplock_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002449 pSMB->AndXCommand = 0xFF; /* none */
2450 pSMB->Fid = smb_file_id; /* netfid stays le */
2451
Steve French790fe572007-07-07 19:25:05 +00002452 if ((numLock != 0) || (numUnlock != 0)) {
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002453 pSMB->Locks[0].Pid = cpu_to_le16(netpid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002454 /* BB where to store pid high? */
2455 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
2456 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
2457 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
2458 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
2459 count = sizeof(LOCKING_ANDX_RANGE);
2460 } else {
2461 /* oplock break */
2462 count = 0;
2463 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002464 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002465 pSMB->ByteCount = cpu_to_le16(count);
2466
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002467 if (waitFlag) {
2468 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002469 (struct smb_hdr *) pSMB, &bytes_returned);
Steve French133672e2007-11-13 22:41:37 +00002470 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002471 } else {
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002472 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, timeout);
Steve French133672e2007-11-13 22:41:37 +00002473 /* SMB buffer freed by function above */
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002474 }
Steve Frencha4544342005-08-24 13:59:35 -07002475 cifs_stats_inc(&tcon->num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002476 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002477 cFYI(1, "Send error in Lock = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002478
Steve French50c2f752007-07-13 00:33:32 +00002479 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002480 since file handle passed in no longer valid */
2481 return rc;
2482}
2483
2484int
Steve French96daf2b2011-05-27 04:34:02 +00002485CIFSSMBPosixLock(const int xid, struct cifs_tcon *tcon,
Pavel Shilovsky4f6bcec2011-10-22 15:33:30 +04002486 const __u16 smb_file_id, const __u32 netpid, const int get_flag,
2487 const __u64 len, struct file_lock *pLockData,
2488 const __u16 lock_type, const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00002489{
2490 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2491 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00002492 struct cifs_posix_lock *parm_data;
2493 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00002494 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00002495 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00002496 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00002497 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00002498 struct kvec iov[1];
Steve French08547b02006-02-28 22:39:25 +00002499
Joe Perchesb6b38f72010-04-21 03:50:45 +00002500 cFYI(1, "Posix Lock");
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002501
Steve French790fe572007-07-07 19:25:05 +00002502 if (pLockData == NULL)
Marcin Slusarzed5f0372008-05-13 04:01:01 +00002503 return -EINVAL;
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002504
Steve French08547b02006-02-28 22:39:25 +00002505 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
2506
2507 if (rc)
2508 return rc;
2509
2510 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
2511
Steve French50c2f752007-07-13 00:33:32 +00002512 params = 6;
Steve French08547b02006-02-28 22:39:25 +00002513 pSMB->MaxSetupCount = 0;
2514 pSMB->Reserved = 0;
2515 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00002516 pSMB->Reserved2 = 0;
2517 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2518 offset = param_offset + params;
2519
Steve French08547b02006-02-28 22:39:25 +00002520 count = sizeof(struct cifs_posix_lock);
2521 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002522 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00002523 pSMB->SetupCount = 1;
2524 pSMB->Reserved3 = 0;
Steve French790fe572007-07-07 19:25:05 +00002525 if (get_flag)
Steve French08547b02006-02-28 22:39:25 +00002526 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2527 else
2528 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2529 byte_count = 3 /* pad */ + params + count;
2530 pSMB->DataCount = cpu_to_le16(count);
2531 pSMB->ParameterCount = cpu_to_le16(params);
2532 pSMB->TotalDataCount = pSMB->DataCount;
2533 pSMB->TotalParameterCount = pSMB->ParameterCount;
2534 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00002535 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00002536 (((char *) &pSMB->hdr.Protocol) + offset);
2537
2538 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00002539 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00002540 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00002541 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00002542 pSMB->Timeout = cpu_to_le32(-1);
2543 } else
2544 pSMB->Timeout = 0;
2545
Pavel Shilovsky4f6bcec2011-10-22 15:33:30 +04002546 parm_data->pid = cpu_to_le32(netpid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002547 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00002548 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00002549
2550 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00002551 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00002552 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
2553 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002554 inc_rfc1001_len(pSMB, byte_count);
Steve French08547b02006-02-28 22:39:25 +00002555 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002556 if (waitFlag) {
2557 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2558 (struct smb_hdr *) pSMBr, &bytes_returned);
2559 } else {
Steve French133672e2007-11-13 22:41:37 +00002560 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002561 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French133672e2007-11-13 22:41:37 +00002562 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
2563 &resp_buf_type, timeout);
2564 pSMB = NULL; /* request buf already freed by SendReceive2. Do
2565 not try to free it twice below on exit */
2566 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002567 }
2568
Steve French08547b02006-02-28 22:39:25 +00002569 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002570 cFYI(1, "Send error in Posix Lock = %d", rc);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002571 } else if (get_flag) {
2572 /* lock structure can be returned on get */
2573 __u16 data_offset;
2574 __u16 data_count;
2575 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00002576
Jeff Layton820a8032011-05-04 08:05:26 -04002577 if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002578 rc = -EIO; /* bad smb */
2579 goto plk_err_exit;
2580 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002581 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2582 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00002583 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002584 rc = -EIO;
2585 goto plk_err_exit;
2586 }
2587 parm_data = (struct cifs_posix_lock *)
2588 ((char *)&pSMBr->hdr.Protocol + data_offset);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002589 if (parm_data->lock_type == __constant_cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002590 pLockData->fl_type = F_UNLCK;
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002591 else {
2592 if (parm_data->lock_type ==
2593 __constant_cpu_to_le16(CIFS_RDLCK))
2594 pLockData->fl_type = F_RDLCK;
2595 else if (parm_data->lock_type ==
2596 __constant_cpu_to_le16(CIFS_WRLCK))
2597 pLockData->fl_type = F_WRLCK;
2598
Steve French5443d132011-03-13 05:08:25 +00002599 pLockData->fl_start = le64_to_cpu(parm_data->start);
2600 pLockData->fl_end = pLockData->fl_start +
2601 le64_to_cpu(parm_data->length) - 1;
2602 pLockData->fl_pid = le32_to_cpu(parm_data->pid);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002603 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002604 }
Steve French50c2f752007-07-13 00:33:32 +00002605
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002606plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00002607 if (pSMB)
2608 cifs_small_buf_release(pSMB);
2609
Steve French133672e2007-11-13 22:41:37 +00002610 if (resp_buf_type == CIFS_SMALL_BUFFER)
2611 cifs_small_buf_release(iov[0].iov_base);
2612 else if (resp_buf_type == CIFS_LARGE_BUFFER)
2613 cifs_buf_release(iov[0].iov_base);
2614
Steve French08547b02006-02-28 22:39:25 +00002615 /* Note: On -EAGAIN error only caller can retry on handle based calls
2616 since file handle passed in no longer valid */
2617
2618 return rc;
2619}
2620
2621
2622int
Steve French96daf2b2011-05-27 04:34:02 +00002623CIFSSMBClose(const int xid, struct cifs_tcon *tcon, int smb_file_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002624{
2625 int rc = 0;
2626 CLOSE_REQ *pSMB = NULL;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002627 cFYI(1, "In CIFSSMBClose");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002628
2629/* do not retry on dead session on close */
2630 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00002631 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002632 return 0;
2633 if (rc)
2634 return rc;
2635
Linus Torvalds1da177e2005-04-16 15:20:36 -07002636 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e2006-10-02 05:53:29 +00002637 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002638 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002639 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002640 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002641 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00002642 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002643 /* EINTR is expected when user ctl-c to kill app */
Joe Perchesb6b38f72010-04-21 03:50:45 +00002644 cERROR(1, "Send error in Close = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002645 }
2646 }
2647
Linus Torvalds1da177e2005-04-16 15:20:36 -07002648 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00002649 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002650 rc = 0;
2651
2652 return rc;
2653}
2654
2655int
Steve French96daf2b2011-05-27 04:34:02 +00002656CIFSSMBFlush(const int xid, struct cifs_tcon *tcon, int smb_file_id)
Steve Frenchb298f222009-02-21 21:17:43 +00002657{
2658 int rc = 0;
2659 FLUSH_REQ *pSMB = NULL;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002660 cFYI(1, "In CIFSSMBFlush");
Steve Frenchb298f222009-02-21 21:17:43 +00002661
2662 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
2663 if (rc)
2664 return rc;
2665
2666 pSMB->FileID = (__u16) smb_file_id;
2667 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002668 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frenchb298f222009-02-21 21:17:43 +00002669 cifs_stats_inc(&tcon->num_flushes);
2670 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002671 cERROR(1, "Send error in Flush = %d", rc);
Steve Frenchb298f222009-02-21 21:17:43 +00002672
2673 return rc;
2674}
2675
2676int
Steve French96daf2b2011-05-27 04:34:02 +00002677CIFSSMBRename(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002678 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002679 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002680{
2681 int rc = 0;
2682 RENAME_REQ *pSMB = NULL;
2683 RENAME_RSP *pSMBr = NULL;
2684 int bytes_returned;
2685 int name_len, name_len2;
2686 __u16 count;
2687
Joe Perchesb6b38f72010-04-21 03:50:45 +00002688 cFYI(1, "In CIFSSMBRename");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002689renameRetry:
2690 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
2691 (void **) &pSMBr);
2692 if (rc)
2693 return rc;
2694
2695 pSMB->BufferFormat = 0x04;
2696 pSMB->SearchAttributes =
2697 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2698 ATTR_DIRECTORY);
2699
2700 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2701 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06002702 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, fromName,
2703 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704 name_len++; /* trailing null */
2705 name_len *= 2;
2706 pSMB->OldFileName[name_len] = 0x04; /* pad */
2707 /* protocol requires ASCII signature byte on Unicode string */
2708 pSMB->OldFileName[name_len + 1] = 0x00;
2709 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002710 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2711 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002712 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2713 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002714 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002715 name_len = strnlen(fromName, PATH_MAX);
2716 name_len++; /* trailing null */
2717 strncpy(pSMB->OldFileName, fromName, name_len);
2718 name_len2 = strnlen(toName, PATH_MAX);
2719 name_len2++; /* trailing null */
2720 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2721 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2722 name_len2++; /* trailing null */
2723 name_len2++; /* signature byte */
2724 }
2725
2726 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002727 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002728 pSMB->ByteCount = cpu_to_le16(count);
2729
2730 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2731 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002732 cifs_stats_inc(&tcon->num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002733 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002734 cFYI(1, "Send error in rename = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735
Linus Torvalds1da177e2005-04-16 15:20:36 -07002736 cifs_buf_release(pSMB);
2737
2738 if (rc == -EAGAIN)
2739 goto renameRetry;
2740
2741 return rc;
2742}
2743
Steve French96daf2b2011-05-27 04:34:02 +00002744int CIFSSMBRenameOpenFile(const int xid, struct cifs_tcon *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002745 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002746 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002747{
2748 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2749 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002750 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002751 char *data_offset;
2752 char dummy_string[30];
2753 int rc = 0;
2754 int bytes_returned = 0;
2755 int len_of_str;
2756 __u16 params, param_offset, offset, count, byte_count;
2757
Joe Perchesb6b38f72010-04-21 03:50:45 +00002758 cFYI(1, "Rename to File by handle");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002759 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2760 (void **) &pSMBr);
2761 if (rc)
2762 return rc;
2763
2764 params = 6;
2765 pSMB->MaxSetupCount = 0;
2766 pSMB->Reserved = 0;
2767 pSMB->Flags = 0;
2768 pSMB->Timeout = 0;
2769 pSMB->Reserved2 = 0;
2770 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2771 offset = param_offset + params;
2772
2773 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2774 rename_info = (struct set_file_rename *) data_offset;
2775 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002776 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002777 pSMB->SetupCount = 1;
2778 pSMB->Reserved3 = 0;
2779 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2780 byte_count = 3 /* pad */ + params;
2781 pSMB->ParameterCount = cpu_to_le16(params);
2782 pSMB->TotalParameterCount = pSMB->ParameterCount;
2783 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2784 pSMB->DataOffset = cpu_to_le16(offset);
2785 /* construct random name ".cifs_tmp<inodenum><mid>" */
2786 rename_info->overwrite = cpu_to_le32(1);
2787 rename_info->root_fid = 0;
2788 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002789 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002790 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
Steve Frenchacbbb762012-01-18 22:32:33 -06002791 len_of_str =
2792 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002793 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002794 } else {
Steve Frenchacbbb762012-01-18 22:32:33 -06002795 len_of_str =
2796 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002797 target_name, PATH_MAX, nls_codepage,
2798 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002799 }
2800 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002801 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002802 byte_count += count;
2803 pSMB->DataCount = cpu_to_le16(count);
2804 pSMB->TotalDataCount = pSMB->DataCount;
2805 pSMB->Fid = netfid;
2806 pSMB->InformationLevel =
2807 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2808 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002809 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002810 pSMB->ByteCount = cpu_to_le16(byte_count);
2811 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002812 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002813 cifs_stats_inc(&pTcon->num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002814 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002815 cFYI(1, "Send error in Rename (by file handle) = %d", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07002816
Linus Torvalds1da177e2005-04-16 15:20:36 -07002817 cifs_buf_release(pSMB);
2818
2819 /* Note: On -EAGAIN error only caller can retry on handle based calls
2820 since file handle passed in no longer valid */
2821
2822 return rc;
2823}
2824
2825int
Steve French96daf2b2011-05-27 04:34:02 +00002826CIFSSMBCopy(const int xid, struct cifs_tcon *tcon, const char *fromName,
Steve French50c2f752007-07-13 00:33:32 +00002827 const __u16 target_tid, const char *toName, const int flags,
2828 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002829{
2830 int rc = 0;
2831 COPY_REQ *pSMB = NULL;
2832 COPY_RSP *pSMBr = NULL;
2833 int bytes_returned;
2834 int name_len, name_len2;
2835 __u16 count;
2836
Joe Perchesb6b38f72010-04-21 03:50:45 +00002837 cFYI(1, "In CIFSSMBCopy");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002838copyRetry:
2839 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2840 (void **) &pSMBr);
2841 if (rc)
2842 return rc;
2843
2844 pSMB->BufferFormat = 0x04;
2845 pSMB->Tid2 = target_tid;
2846
2847 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2848
2849 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002850 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2851 fromName, PATH_MAX, nls_codepage,
2852 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002853 name_len++; /* trailing null */
2854 name_len *= 2;
2855 pSMB->OldFileName[name_len] = 0x04; /* pad */
2856 /* protocol requires ASCII signature byte on Unicode string */
2857 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002858 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002859 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2860 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002861 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2862 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002863 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002864 name_len = strnlen(fromName, PATH_MAX);
2865 name_len++; /* trailing null */
2866 strncpy(pSMB->OldFileName, fromName, name_len);
2867 name_len2 = strnlen(toName, PATH_MAX);
2868 name_len2++; /* trailing null */
2869 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2870 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2871 name_len2++; /* trailing null */
2872 name_len2++; /* signature byte */
2873 }
2874
2875 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002876 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002877 pSMB->ByteCount = cpu_to_le16(count);
2878
2879 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2880 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2881 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002882 cFYI(1, "Send error in copy = %d with %d files copied",
2883 rc, le16_to_cpu(pSMBr->CopyCount));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002884 }
Steve French0d817bc2008-05-22 02:02:03 +00002885 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002886
2887 if (rc == -EAGAIN)
2888 goto copyRetry;
2889
2890 return rc;
2891}
2892
2893int
Steve French96daf2b2011-05-27 04:34:02 +00002894CIFSUnixCreateSymLink(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002895 const char *fromName, const char *toName,
2896 const struct nls_table *nls_codepage)
2897{
2898 TRANSACTION2_SPI_REQ *pSMB = NULL;
2899 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2900 char *data_offset;
2901 int name_len;
2902 int name_len_target;
2903 int rc = 0;
2904 int bytes_returned = 0;
2905 __u16 params, param_offset, offset, byte_count;
2906
Joe Perchesb6b38f72010-04-21 03:50:45 +00002907 cFYI(1, "In Symlink Unix style");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002908createSymLinkRetry:
2909 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2910 (void **) &pSMBr);
2911 if (rc)
2912 return rc;
2913
2914 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2915 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06002916 cifs_strtoUTF16((__le16 *) pSMB->FileName, fromName,
2917 /* find define for this maxpathcomponent */
2918 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002919 name_len++; /* trailing null */
2920 name_len *= 2;
2921
Steve French50c2f752007-07-13 00:33:32 +00002922 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002923 name_len = strnlen(fromName, PATH_MAX);
2924 name_len++; /* trailing null */
2925 strncpy(pSMB->FileName, fromName, name_len);
2926 }
2927 params = 6 + name_len;
2928 pSMB->MaxSetupCount = 0;
2929 pSMB->Reserved = 0;
2930 pSMB->Flags = 0;
2931 pSMB->Timeout = 0;
2932 pSMB->Reserved2 = 0;
2933 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002934 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002935 offset = param_offset + params;
2936
2937 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2938 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2939 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06002940 cifs_strtoUTF16((__le16 *) data_offset, toName, PATH_MAX
2941 /* find define for this maxpathcomponent */
2942 , nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002943 name_len_target++; /* trailing null */
2944 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002945 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002946 name_len_target = strnlen(toName, PATH_MAX);
2947 name_len_target++; /* trailing null */
2948 strncpy(data_offset, toName, name_len_target);
2949 }
2950
2951 pSMB->MaxParameterCount = cpu_to_le16(2);
2952 /* BB find exact max on data count below from sess */
2953 pSMB->MaxDataCount = cpu_to_le16(1000);
2954 pSMB->SetupCount = 1;
2955 pSMB->Reserved3 = 0;
2956 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2957 byte_count = 3 /* pad */ + params + name_len_target;
2958 pSMB->DataCount = cpu_to_le16(name_len_target);
2959 pSMB->ParameterCount = cpu_to_le16(params);
2960 pSMB->TotalDataCount = pSMB->DataCount;
2961 pSMB->TotalParameterCount = pSMB->ParameterCount;
2962 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2963 pSMB->DataOffset = cpu_to_le16(offset);
2964 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2965 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002966 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002967 pSMB->ByteCount = cpu_to_le16(byte_count);
2968 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2969 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002970 cifs_stats_inc(&tcon->num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002971 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002972 cFYI(1, "Send error in SetPathInfo create symlink = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002973
Steve French0d817bc2008-05-22 02:02:03 +00002974 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002975
2976 if (rc == -EAGAIN)
2977 goto createSymLinkRetry;
2978
2979 return rc;
2980}
2981
2982int
Steve French96daf2b2011-05-27 04:34:02 +00002983CIFSUnixCreateHardLink(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002984 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002985 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002986{
2987 TRANSACTION2_SPI_REQ *pSMB = NULL;
2988 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2989 char *data_offset;
2990 int name_len;
2991 int name_len_target;
2992 int rc = 0;
2993 int bytes_returned = 0;
2994 __u16 params, param_offset, offset, byte_count;
2995
Joe Perchesb6b38f72010-04-21 03:50:45 +00002996 cFYI(1, "In Create Hard link Unix style");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002997createHardLinkRetry:
2998 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2999 (void **) &pSMBr);
3000 if (rc)
3001 return rc;
3002
3003 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06003004 name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, toName,
3005 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003006 name_len++; /* trailing null */
3007 name_len *= 2;
3008
Steve French50c2f752007-07-13 00:33:32 +00003009 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003010 name_len = strnlen(toName, PATH_MAX);
3011 name_len++; /* trailing null */
3012 strncpy(pSMB->FileName, toName, name_len);
3013 }
3014 params = 6 + name_len;
3015 pSMB->MaxSetupCount = 0;
3016 pSMB->Reserved = 0;
3017 pSMB->Flags = 0;
3018 pSMB->Timeout = 0;
3019 pSMB->Reserved2 = 0;
3020 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003021 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003022 offset = param_offset + params;
3023
3024 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
3025 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3026 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06003027 cifsConvertToUTF16((__le16 *) data_offset, fromName,
3028 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003029 name_len_target++; /* trailing null */
3030 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003031 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003032 name_len_target = strnlen(fromName, PATH_MAX);
3033 name_len_target++; /* trailing null */
3034 strncpy(data_offset, fromName, name_len_target);
3035 }
3036
3037 pSMB->MaxParameterCount = cpu_to_le16(2);
3038 /* BB find exact max on data count below from sess*/
3039 pSMB->MaxDataCount = cpu_to_le16(1000);
3040 pSMB->SetupCount = 1;
3041 pSMB->Reserved3 = 0;
3042 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3043 byte_count = 3 /* pad */ + params + name_len_target;
3044 pSMB->ParameterCount = cpu_to_le16(params);
3045 pSMB->TotalParameterCount = pSMB->ParameterCount;
3046 pSMB->DataCount = cpu_to_le16(name_len_target);
3047 pSMB->TotalDataCount = pSMB->DataCount;
3048 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3049 pSMB->DataOffset = cpu_to_le16(offset);
3050 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
3051 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003052 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003053 pSMB->ByteCount = cpu_to_le16(byte_count);
3054 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3055 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003056 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00003057 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003058 cFYI(1, "Send error in SetPathInfo (hard link) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003059
3060 cifs_buf_release(pSMB);
3061 if (rc == -EAGAIN)
3062 goto createHardLinkRetry;
3063
3064 return rc;
3065}
3066
3067int
Steve French96daf2b2011-05-27 04:34:02 +00003068CIFSCreateHardLink(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003069 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07003070 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003071{
3072 int rc = 0;
3073 NT_RENAME_REQ *pSMB = NULL;
3074 RENAME_RSP *pSMBr = NULL;
3075 int bytes_returned;
3076 int name_len, name_len2;
3077 __u16 count;
3078
Joe Perchesb6b38f72010-04-21 03:50:45 +00003079 cFYI(1, "In CIFSCreateHardLink");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003080winCreateHardLinkRetry:
3081
3082 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
3083 (void **) &pSMBr);
3084 if (rc)
3085 return rc;
3086
3087 pSMB->SearchAttributes =
3088 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3089 ATTR_DIRECTORY);
3090 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
3091 pSMB->ClusterCount = 0;
3092
3093 pSMB->BufferFormat = 0x04;
3094
3095 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3096 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003097 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, fromName,
3098 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003099 name_len++; /* trailing null */
3100 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05003101
3102 /* protocol specifies ASCII buffer format (0x04) for unicode */
3103 pSMB->OldFileName[name_len] = 0x04;
3104 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003105 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06003106 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
3107 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003108 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
3109 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00003110 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003111 name_len = strnlen(fromName, PATH_MAX);
3112 name_len++; /* trailing null */
3113 strncpy(pSMB->OldFileName, fromName, name_len);
3114 name_len2 = strnlen(toName, PATH_MAX);
3115 name_len2++; /* trailing null */
3116 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
3117 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
3118 name_len2++; /* trailing null */
3119 name_len2++; /* signature byte */
3120 }
3121
3122 count = 1 /* string type byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003123 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003124 pSMB->ByteCount = cpu_to_le16(count);
3125
3126 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3127 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003128 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00003129 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003130 cFYI(1, "Send error in hard link (NT rename) = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00003131
Linus Torvalds1da177e2005-04-16 15:20:36 -07003132 cifs_buf_release(pSMB);
3133 if (rc == -EAGAIN)
3134 goto winCreateHardLinkRetry;
3135
3136 return rc;
3137}
3138
3139int
Steve French96daf2b2011-05-27 04:34:02 +00003140CIFSSMBUnixQuerySymLink(const int xid, struct cifs_tcon *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04003141 const unsigned char *searchName, char **symlinkinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003142 const struct nls_table *nls_codepage)
3143{
3144/* SMB_QUERY_FILE_UNIX_LINK */
3145 TRANSACTION2_QPI_REQ *pSMB = NULL;
3146 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3147 int rc = 0;
3148 int bytes_returned;
3149 int name_len;
3150 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04003151 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003152
Joe Perchesb6b38f72010-04-21 03:50:45 +00003153 cFYI(1, "In QPathSymLinkInfo (Unix) for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003154
3155querySymLinkRetry:
3156 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3157 (void **) &pSMBr);
3158 if (rc)
3159 return rc;
3160
3161 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3162 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003163 cifs_strtoUTF16((__le16 *) pSMB->FileName, searchName,
3164 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003165 name_len++; /* trailing null */
3166 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003167 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003168 name_len = strnlen(searchName, PATH_MAX);
3169 name_len++; /* trailing null */
3170 strncpy(pSMB->FileName, searchName, name_len);
3171 }
3172
3173 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3174 pSMB->TotalDataCount = 0;
3175 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04003176 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003177 pSMB->MaxSetupCount = 0;
3178 pSMB->Reserved = 0;
3179 pSMB->Flags = 0;
3180 pSMB->Timeout = 0;
3181 pSMB->Reserved2 = 0;
3182 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003183 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003184 pSMB->DataCount = 0;
3185 pSMB->DataOffset = 0;
3186 pSMB->SetupCount = 1;
3187 pSMB->Reserved3 = 0;
3188 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3189 byte_count = params + 1 /* pad */ ;
3190 pSMB->TotalParameterCount = cpu_to_le16(params);
3191 pSMB->ParameterCount = pSMB->TotalParameterCount;
3192 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
3193 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003194 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003195 pSMB->ByteCount = cpu_to_le16(byte_count);
3196
3197 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3198 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3199 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003200 cFYI(1, "Send error in QuerySymLinkInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003201 } else {
3202 /* decode response */
3203
3204 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003205 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003206 if (rc || get_bcc(&pSMBr->hdr) < 2)
Jeff Layton460b9692009-04-30 07:17:56 -04003207 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003208 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00003209 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04003210 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003211
Jeff Layton460b9692009-04-30 07:17:56 -04003212 data_start = ((char *) &pSMBr->hdr.Protocol) +
3213 le16_to_cpu(pSMBr->t2.DataOffset);
3214
Steve French0e0d2cf2009-05-01 05:27:32 +00003215 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3216 is_unicode = true;
3217 else
3218 is_unicode = false;
3219
Steve French737b7582005-04-28 22:41:06 -07003220 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchacbbb762012-01-18 22:32:33 -06003221 *symlinkinfo = cifs_strndup_from_utf16(data_start,
3222 count, is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04003223 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04003224 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003225 }
3226 }
3227 cifs_buf_release(pSMB);
3228 if (rc == -EAGAIN)
3229 goto querySymLinkRetry;
3230 return rc;
3231}
3232
Steve Frenchc52a9552011-02-24 06:16:22 +00003233#ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL
3234/*
3235 * Recent Windows versions now create symlinks more frequently
3236 * and they use the "reparse point" mechanism below. We can of course
3237 * do symlinks nicely to Samba and other servers which support the
3238 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
3239 * "MF" symlinks optionally, but for recent Windows we really need to
3240 * reenable the code below and fix the cifs_symlink callers to handle this.
3241 * In the interim this code has been moved to its own config option so
3242 * it is not compiled in by default until callers fixed up and more tested.
3243 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003244int
Steve French96daf2b2011-05-27 04:34:02 +00003245CIFSSMBQueryReparseLinkInfo(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003246 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00003247 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003248 const struct nls_table *nls_codepage)
3249{
3250 int rc = 0;
3251 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00003252 struct smb_com_transaction_ioctl_req *pSMB;
3253 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003254
Joe Perchesb6b38f72010-04-21 03:50:45 +00003255 cFYI(1, "In Windows reparse style QueryLink for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003256 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3257 (void **) &pSMBr);
3258 if (rc)
3259 return rc;
3260
3261 pSMB->TotalParameterCount = 0 ;
3262 pSMB->TotalDataCount = 0;
3263 pSMB->MaxParameterCount = cpu_to_le32(2);
3264 /* BB find exact data count max from sess structure BB */
Jeff Laytonc974bef2011-10-11 06:41:32 -04003265 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003266 pSMB->MaxSetupCount = 4;
3267 pSMB->Reserved = 0;
3268 pSMB->ParameterOffset = 0;
3269 pSMB->DataCount = 0;
3270 pSMB->DataOffset = 0;
3271 pSMB->SetupCount = 4;
3272 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
3273 pSMB->ParameterCount = pSMB->TotalParameterCount;
3274 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
3275 pSMB->IsFsctl = 1; /* FSCTL */
3276 pSMB->IsRootFlag = 0;
3277 pSMB->Fid = fid; /* file handle always le */
3278 pSMB->ByteCount = 0;
3279
3280 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3281 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3282 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003283 cFYI(1, "Send error in QueryReparseLinkInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003284 } else { /* decode response */
3285 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
3286 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
Jeff Layton820a8032011-05-04 08:05:26 -04003287 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
3288 /* BB also check enough total bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003289 rc = -EIO; /* bad smb */
Steve Frenchafe48c32009-05-02 05:25:46 +00003290 goto qreparse_out;
3291 }
3292 if (data_count && (data_count < 2048)) {
3293 char *end_of_smb = 2 /* sizeof byte count */ +
Jeff Layton820a8032011-05-04 08:05:26 -04003294 get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003295
Steve Frenchafe48c32009-05-02 05:25:46 +00003296 struct reparse_data *reparse_buf =
Steve French50c2f752007-07-13 00:33:32 +00003297 (struct reparse_data *)
3298 ((char *)&pSMBr->hdr.Protocol
3299 + data_offset);
Steve Frenchafe48c32009-05-02 05:25:46 +00003300 if ((char *)reparse_buf >= end_of_smb) {
3301 rc = -EIO;
3302 goto qreparse_out;
3303 }
3304 if ((reparse_buf->LinkNamesBuf +
3305 reparse_buf->TargetNameOffset +
3306 reparse_buf->TargetNameLen) > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003307 cFYI(1, "reparse buf beyond SMB");
Steve Frenchafe48c32009-05-02 05:25:46 +00003308 rc = -EIO;
3309 goto qreparse_out;
3310 }
Steve French50c2f752007-07-13 00:33:32 +00003311
Steve Frenchafe48c32009-05-02 05:25:46 +00003312 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3313 cifs_from_ucs2(symlinkinfo, (__le16 *)
Steve French50c2f752007-07-13 00:33:32 +00003314 (reparse_buf->LinkNamesBuf +
3315 reparse_buf->TargetNameOffset),
Steve Frenchafe48c32009-05-02 05:25:46 +00003316 buflen,
3317 reparse_buf->TargetNameLen,
3318 nls_codepage, 0);
3319 } else { /* ASCII names */
3320 strncpy(symlinkinfo,
3321 reparse_buf->LinkNamesBuf +
3322 reparse_buf->TargetNameOffset,
3323 min_t(const int, buflen,
3324 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003325 }
Steve Frenchafe48c32009-05-02 05:25:46 +00003326 } else {
3327 rc = -EIO;
Joe Perchesb6b38f72010-04-21 03:50:45 +00003328 cFYI(1, "Invalid return data count on "
3329 "get reparse info ioctl");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003330 }
Steve Frenchafe48c32009-05-02 05:25:46 +00003331 symlinkinfo[buflen] = 0; /* just in case so the caller
3332 does not go off the end of the buffer */
Joe Perchesb6b38f72010-04-21 03:50:45 +00003333 cFYI(1, "readlink result - %s", symlinkinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003334 }
Steve French989c7e52009-05-02 05:32:20 +00003335
Linus Torvalds1da177e2005-04-16 15:20:36 -07003336qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07003337 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003338
3339 /* Note: On -EAGAIN error only caller can retry on handle based calls
3340 since file handle passed in no longer valid */
3341
3342 return rc;
3343}
Steve Frenchc52a9552011-02-24 06:16:22 +00003344#endif /* CIFS_SYMLINK_EXPERIMENTAL */ /* BB temporarily unused */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003345
3346#ifdef CONFIG_CIFS_POSIX
3347
3348/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00003349static void cifs_convert_ace(posix_acl_xattr_entry *ace,
3350 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003351{
3352 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08003353 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
3354 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
3355 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesb6b38f72010-04-21 03:50:45 +00003356 /* cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003357
3358 return;
3359}
3360
3361/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00003362static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
3363 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003364{
3365 int size = 0;
3366 int i;
3367 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00003368 struct cifs_posix_ace *pACE;
3369 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
3370 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003371
3372 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
3373 return -EOPNOTSUPP;
3374
Steve French790fe572007-07-07 19:25:05 +00003375 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003376 count = le16_to_cpu(cifs_acl->access_entry_count);
3377 pACE = &cifs_acl->ace_array[0];
3378 size = sizeof(struct cifs_posix_acl);
3379 size += sizeof(struct cifs_posix_ace) * count;
3380 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003381 if (size_of_data_area < size) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003382 cFYI(1, "bad CIFS POSIX ACL size %d vs. %d",
3383 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003384 return -EINVAL;
3385 }
Steve French790fe572007-07-07 19:25:05 +00003386 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003387 count = le16_to_cpu(cifs_acl->access_entry_count);
3388 size = sizeof(struct cifs_posix_acl);
3389 size += sizeof(struct cifs_posix_ace) * count;
3390/* skip past access ACEs to get to default ACEs */
3391 pACE = &cifs_acl->ace_array[count];
3392 count = le16_to_cpu(cifs_acl->default_entry_count);
3393 size += sizeof(struct cifs_posix_ace) * count;
3394 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003395 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003396 return -EINVAL;
3397 } else {
3398 /* illegal type */
3399 return -EINVAL;
3400 }
3401
3402 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00003403 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00003404 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00003405 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003406 return -ERANGE;
3407 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08003408 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00003409 for (i = 0; i < count ; i++) {
3410 cifs_convert_ace(&local_acl->a_entries[i], pACE);
3411 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003412 }
3413 }
3414 return size;
3415}
3416
Steve French50c2f752007-07-13 00:33:32 +00003417static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
3418 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003419{
3420 __u16 rc = 0; /* 0 = ACL converted ok */
3421
Steve Frenchff7feac2005-11-15 16:45:16 -08003422 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
3423 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003424 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00003425 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003426 /* Probably no need to le convert -1 on any arch but can not hurt */
3427 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00003428 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08003429 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesb6b38f72010-04-21 03:50:45 +00003430 /*cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id);*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003431 return rc;
3432}
3433
3434/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00003435static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
3436 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003437{
3438 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00003439 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
3440 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003441 int count;
3442 int i;
3443
Steve French790fe572007-07-07 19:25:05 +00003444 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003445 return 0;
3446
3447 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesb6b38f72010-04-21 03:50:45 +00003448 cFYI(1, "setting acl with %d entries from buf of length %d and "
Steve French63135e02007-07-17 17:34:02 +00003449 "version of %d",
Joe Perchesb6b38f72010-04-21 03:50:45 +00003450 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00003451 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003452 cFYI(1, "unknown POSIX ACL version %d",
3453 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003454 return 0;
3455 }
3456 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00003457 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08003458 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00003459 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08003460 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003461 else {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003462 cFYI(1, "unknown ACL type %d", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003463 return 0;
3464 }
Steve French50c2f752007-07-13 00:33:32 +00003465 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003466 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
3467 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00003468 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003469 /* ACE not converted */
3470 break;
3471 }
3472 }
Steve French790fe572007-07-07 19:25:05 +00003473 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003474 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
3475 rc += sizeof(struct cifs_posix_acl);
3476 /* BB add check to make sure ACL does not overflow SMB */
3477 }
3478 return rc;
3479}
3480
3481int
Steve French96daf2b2011-05-27 04:34:02 +00003482CIFSSMBGetPosixACL(const int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003483 const unsigned char *searchName,
3484 char *acl_inf, const int buflen, const int acl_type,
3485 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003486{
3487/* SMB_QUERY_POSIX_ACL */
3488 TRANSACTION2_QPI_REQ *pSMB = NULL;
3489 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3490 int rc = 0;
3491 int bytes_returned;
3492 int name_len;
3493 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00003494
Joe Perchesb6b38f72010-04-21 03:50:45 +00003495 cFYI(1, "In GetPosixACL (Unix) for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003496
3497queryAclRetry:
3498 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3499 (void **) &pSMBr);
3500 if (rc)
3501 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003502
Linus Torvalds1da177e2005-04-16 15:20:36 -07003503 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3504 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003505 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3506 searchName, PATH_MAX, nls_codepage,
3507 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003508 name_len++; /* trailing null */
3509 name_len *= 2;
3510 pSMB->FileName[name_len] = 0;
3511 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00003512 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003513 name_len = strnlen(searchName, PATH_MAX);
3514 name_len++; /* trailing null */
3515 strncpy(pSMB->FileName, searchName, name_len);
3516 }
3517
3518 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3519 pSMB->TotalDataCount = 0;
3520 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00003521 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003522 pSMB->MaxDataCount = cpu_to_le16(4000);
3523 pSMB->MaxSetupCount = 0;
3524 pSMB->Reserved = 0;
3525 pSMB->Flags = 0;
3526 pSMB->Timeout = 0;
3527 pSMB->Reserved2 = 0;
3528 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003529 offsetof(struct smb_com_transaction2_qpi_req,
3530 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003531 pSMB->DataCount = 0;
3532 pSMB->DataOffset = 0;
3533 pSMB->SetupCount = 1;
3534 pSMB->Reserved3 = 0;
3535 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3536 byte_count = params + 1 /* pad */ ;
3537 pSMB->TotalParameterCount = cpu_to_le16(params);
3538 pSMB->ParameterCount = pSMB->TotalParameterCount;
3539 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
3540 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003541 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003542 pSMB->ByteCount = cpu_to_le16(byte_count);
3543
3544 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3545 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08003546 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003547 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003548 cFYI(1, "Send error in Query POSIX ACL = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003549 } else {
3550 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00003551
Linus Torvalds1da177e2005-04-16 15:20:36 -07003552 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003553 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003554 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003555 rc = -EIO; /* bad smb */
3556 else {
3557 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3558 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3559 rc = cifs_copy_posix_acl(acl_inf,
3560 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00003561 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003562 }
3563 }
3564 cifs_buf_release(pSMB);
3565 if (rc == -EAGAIN)
3566 goto queryAclRetry;
3567 return rc;
3568}
3569
3570int
Steve French96daf2b2011-05-27 04:34:02 +00003571CIFSSMBSetPosixACL(const int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003572 const unsigned char *fileName,
3573 const char *local_acl, const int buflen,
3574 const int acl_type,
3575 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003576{
3577 struct smb_com_transaction2_spi_req *pSMB = NULL;
3578 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3579 char *parm_data;
3580 int name_len;
3581 int rc = 0;
3582 int bytes_returned = 0;
3583 __u16 params, byte_count, data_count, param_offset, offset;
3584
Joe Perchesb6b38f72010-04-21 03:50:45 +00003585 cFYI(1, "In SetPosixACL (Unix) for path %s", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003586setAclRetry:
3587 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003588 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003589 if (rc)
3590 return rc;
3591 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3592 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003593 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
3594 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003595 name_len++; /* trailing null */
3596 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003597 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003598 name_len = strnlen(fileName, PATH_MAX);
3599 name_len++; /* trailing null */
3600 strncpy(pSMB->FileName, fileName, name_len);
3601 }
3602 params = 6 + name_len;
3603 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003604 /* BB find max SMB size from sess */
3605 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003606 pSMB->MaxSetupCount = 0;
3607 pSMB->Reserved = 0;
3608 pSMB->Flags = 0;
3609 pSMB->Timeout = 0;
3610 pSMB->Reserved2 = 0;
3611 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003612 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003613 offset = param_offset + params;
3614 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
3615 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3616
3617 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00003618 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003619
Steve French790fe572007-07-07 19:25:05 +00003620 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003621 rc = -EOPNOTSUPP;
3622 goto setACLerrorExit;
3623 }
3624 pSMB->DataOffset = cpu_to_le16(offset);
3625 pSMB->SetupCount = 1;
3626 pSMB->Reserved3 = 0;
3627 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3628 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
3629 byte_count = 3 /* pad */ + params + data_count;
3630 pSMB->DataCount = cpu_to_le16(data_count);
3631 pSMB->TotalDataCount = pSMB->DataCount;
3632 pSMB->ParameterCount = cpu_to_le16(params);
3633 pSMB->TotalParameterCount = pSMB->ParameterCount;
3634 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003635 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003636 pSMB->ByteCount = cpu_to_le16(byte_count);
3637 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003638 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003639 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003640 cFYI(1, "Set POSIX ACL returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003641
3642setACLerrorExit:
3643 cifs_buf_release(pSMB);
3644 if (rc == -EAGAIN)
3645 goto setAclRetry;
3646 return rc;
3647}
3648
Steve Frenchf654bac2005-04-28 22:41:04 -07003649/* BB fix tabs in this function FIXME BB */
3650int
Steve French96daf2b2011-05-27 04:34:02 +00003651CIFSGetExtAttr(const int xid, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00003652 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07003653{
Steve French50c2f752007-07-13 00:33:32 +00003654 int rc = 0;
3655 struct smb_t2_qfi_req *pSMB = NULL;
3656 struct smb_t2_qfi_rsp *pSMBr = NULL;
3657 int bytes_returned;
3658 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07003659
Joe Perchesb6b38f72010-04-21 03:50:45 +00003660 cFYI(1, "In GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00003661 if (tcon == NULL)
3662 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07003663
3664GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003665 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3666 (void **) &pSMBr);
3667 if (rc)
3668 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003669
Steve Frenchad7a2922008-02-07 23:25:02 +00003670 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003671 pSMB->t2.TotalDataCount = 0;
3672 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3673 /* BB find exact max data count below from sess structure BB */
3674 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3675 pSMB->t2.MaxSetupCount = 0;
3676 pSMB->t2.Reserved = 0;
3677 pSMB->t2.Flags = 0;
3678 pSMB->t2.Timeout = 0;
3679 pSMB->t2.Reserved2 = 0;
3680 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3681 Fid) - 4);
3682 pSMB->t2.DataCount = 0;
3683 pSMB->t2.DataOffset = 0;
3684 pSMB->t2.SetupCount = 1;
3685 pSMB->t2.Reserved3 = 0;
3686 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3687 byte_count = params + 1 /* pad */ ;
3688 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3689 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3690 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3691 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003692 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003693 inc_rfc1001_len(pSMB, byte_count);
Steve French790fe572007-07-07 19:25:05 +00003694 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003695
Steve French790fe572007-07-07 19:25:05 +00003696 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3697 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3698 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003699 cFYI(1, "error %d in GetExtAttr", rc);
Steve French790fe572007-07-07 19:25:05 +00003700 } else {
3701 /* decode response */
3702 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003703 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003704 if (rc || get_bcc(&pSMBr->hdr) < 2)
Steve French790fe572007-07-07 19:25:05 +00003705 /* If rc should we check for EOPNOSUPP and
3706 disable the srvino flag? or in caller? */
3707 rc = -EIO; /* bad smb */
3708 else {
3709 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3710 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3711 struct file_chattr_info *pfinfo;
3712 /* BB Do we need a cast or hash here ? */
3713 if (count != 16) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003714 cFYI(1, "Illegal size ret in GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00003715 rc = -EIO;
3716 goto GetExtAttrOut;
3717 }
3718 pfinfo = (struct file_chattr_info *)
3719 (data_offset + (char *) &pSMBr->hdr.Protocol);
3720 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003721 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003722 }
3723 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003724GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003725 cifs_buf_release(pSMB);
3726 if (rc == -EAGAIN)
3727 goto GetExtAttrRetry;
3728 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003729}
3730
Steve Frenchf654bac2005-04-28 22:41:04 -07003731#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003732
Jeff Layton79df1ba2010-12-06 12:52:08 -05003733#ifdef CONFIG_CIFS_ACL
3734/*
3735 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3736 * all NT TRANSACTS that we init here have total parm and data under about 400
3737 * bytes (to fit in small cifs buffer size), which is the case so far, it
3738 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3739 * returned setup area) and MaxParameterCount (returned parms size) must be set
3740 * by caller
3741 */
3742static int
3743smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French96daf2b2011-05-27 04:34:02 +00003744 const int parm_len, struct cifs_tcon *tcon,
Jeff Layton79df1ba2010-12-06 12:52:08 -05003745 void **ret_buf)
3746{
3747 int rc;
3748 __u32 temp_offset;
3749 struct smb_com_ntransact_req *pSMB;
3750
3751 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3752 (void **)&pSMB);
3753 if (rc)
3754 return rc;
3755 *ret_buf = (void *)pSMB;
3756 pSMB->Reserved = 0;
3757 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3758 pSMB->TotalDataCount = 0;
Jeff Laytonc974bef2011-10-11 06:41:32 -04003759 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003760 pSMB->ParameterCount = pSMB->TotalParameterCount;
3761 pSMB->DataCount = pSMB->TotalDataCount;
3762 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3763 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3764 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3765 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3766 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3767 pSMB->SubCommand = cpu_to_le16(sub_command);
3768 return 0;
3769}
3770
3771static int
3772validate_ntransact(char *buf, char **ppparm, char **ppdata,
3773 __u32 *pparmlen, __u32 *pdatalen)
3774{
3775 char *end_of_smb;
3776 __u32 data_count, data_offset, parm_count, parm_offset;
3777 struct smb_com_ntransact_rsp *pSMBr;
Jeff Layton820a8032011-05-04 08:05:26 -04003778 u16 bcc;
Jeff Layton79df1ba2010-12-06 12:52:08 -05003779
3780 *pdatalen = 0;
3781 *pparmlen = 0;
3782
3783 if (buf == NULL)
3784 return -EINVAL;
3785
3786 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3787
Jeff Layton820a8032011-05-04 08:05:26 -04003788 bcc = get_bcc(&pSMBr->hdr);
3789 end_of_smb = 2 /* sizeof byte count */ + bcc +
Jeff Layton79df1ba2010-12-06 12:52:08 -05003790 (char *)&pSMBr->ByteCount;
3791
3792 data_offset = le32_to_cpu(pSMBr->DataOffset);
3793 data_count = le32_to_cpu(pSMBr->DataCount);
3794 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3795 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3796
3797 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3798 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3799
3800 /* should we also check that parm and data areas do not overlap? */
3801 if (*ppparm > end_of_smb) {
3802 cFYI(1, "parms start after end of smb");
3803 return -EINVAL;
3804 } else if (parm_count + *ppparm > end_of_smb) {
3805 cFYI(1, "parm end after end of smb");
3806 return -EINVAL;
3807 } else if (*ppdata > end_of_smb) {
3808 cFYI(1, "data starts after end of smb");
3809 return -EINVAL;
3810 } else if (data_count + *ppdata > end_of_smb) {
3811 cFYI(1, "data %p + count %d (%p) past smb end %p start %p",
3812 *ppdata, data_count, (data_count + *ppdata),
3813 end_of_smb, pSMBr);
3814 return -EINVAL;
Jeff Layton820a8032011-05-04 08:05:26 -04003815 } else if (parm_count + data_count > bcc) {
Jeff Layton79df1ba2010-12-06 12:52:08 -05003816 cFYI(1, "parm count and data count larger than SMB");
3817 return -EINVAL;
3818 }
3819 *pdatalen = data_count;
3820 *pparmlen = parm_count;
3821 return 0;
3822}
3823
Steve French0a4b92c2006-01-12 15:44:21 -08003824/* Get Security Descriptor (by handle) from remote server for a file or dir */
3825int
Steve French96daf2b2011-05-27 04:34:02 +00003826CIFSSMBGetCIFSACL(const int xid, struct cifs_tcon *tcon, __u16 fid,
Steve French630f3f02007-10-25 21:17:17 +00003827 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003828{
3829 int rc = 0;
3830 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003831 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003832 struct kvec iov[1];
3833
Joe Perchesb6b38f72010-04-21 03:50:45 +00003834 cFYI(1, "GetCifsACL");
Steve French0a4b92c2006-01-12 15:44:21 -08003835
Steve French630f3f02007-10-25 21:17:17 +00003836 *pbuflen = 0;
3837 *acl_inf = NULL;
3838
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003839 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003840 8 /* parm len */, tcon, (void **) &pSMB);
3841 if (rc)
3842 return rc;
3843
3844 pSMB->MaxParameterCount = cpu_to_le32(4);
3845 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3846 pSMB->MaxSetupCount = 0;
3847 pSMB->Fid = fid; /* file handle always le */
3848 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3849 CIFS_ACL_DACL);
3850 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003851 inc_rfc1001_len(pSMB, 11);
Steve French0a4b92c2006-01-12 15:44:21 -08003852 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003853 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French0a4b92c2006-01-12 15:44:21 -08003854
Steve Frencha761ac52007-10-18 21:45:27 +00003855 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Jeff Layton77499812011-01-11 07:24:23 -05003856 0);
Steve French0a4b92c2006-01-12 15:44:21 -08003857 cifs_stats_inc(&tcon->num_acl_get);
3858 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003859 cFYI(1, "Send error in QuerySecDesc = %d", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08003860 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003861 __le32 *parm;
Steve French630f3f02007-10-25 21:17:17 +00003862 __u32 parm_len;
3863 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003864 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f02007-10-25 21:17:17 +00003865 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003866
3867/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003868 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f02007-10-25 21:17:17 +00003869 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003870 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003871 goto qsec_out;
3872 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3873
Joe Perchesb6b38f72010-04-21 03:50:45 +00003874 cFYI(1, "smb %p parm %p data %p", pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08003875
3876 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3877 rc = -EIO; /* bad smb */
Steve French630f3f02007-10-25 21:17:17 +00003878 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003879 goto qsec_out;
3880 }
3881
3882/* BB check that data area is minimum length and as big as acl_len */
3883
Steve Frenchaf6f4612007-10-16 18:40:37 +00003884 acl_len = le32_to_cpu(*parm);
Steve French630f3f02007-10-25 21:17:17 +00003885 if (acl_len != *pbuflen) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003886 cERROR(1, "acl length %d does not match %d",
3887 acl_len, *pbuflen);
Steve French630f3f02007-10-25 21:17:17 +00003888 if (*pbuflen > acl_len)
3889 *pbuflen = acl_len;
3890 }
Steve French0a4b92c2006-01-12 15:44:21 -08003891
Steve French630f3f02007-10-25 21:17:17 +00003892 /* check if buffer is big enough for the acl
3893 header followed by the smallest SID */
3894 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3895 (*pbuflen >= 64 * 1024)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003896 cERROR(1, "bad acl length %d", *pbuflen);
Steve French630f3f02007-10-25 21:17:17 +00003897 rc = -EINVAL;
3898 *pbuflen = 0;
3899 } else {
3900 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3901 if (*acl_inf == NULL) {
3902 *pbuflen = 0;
3903 rc = -ENOMEM;
3904 }
3905 memcpy(*acl_inf, pdata, *pbuflen);
3906 }
Steve French0a4b92c2006-01-12 15:44:21 -08003907 }
3908qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003909 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003910 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003911 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003912 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003913/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003914 return rc;
3915}
Steve French97837582007-12-31 07:47:21 +00003916
3917int
Steve French96daf2b2011-05-27 04:34:02 +00003918CIFSSMBSetCIFSACL(const int xid, struct cifs_tcon *tcon, __u16 fid,
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003919 struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
Steve French97837582007-12-31 07:47:21 +00003920{
3921 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3922 int rc = 0;
3923 int bytes_returned = 0;
3924 SET_SEC_DESC_REQ *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003925 void *pSMBr;
Steve French97837582007-12-31 07:47:21 +00003926
3927setCifsAclRetry:
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003928 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, &pSMBr);
Steve French97837582007-12-31 07:47:21 +00003929 if (rc)
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003930 return rc;
Steve French97837582007-12-31 07:47:21 +00003931
3932 pSMB->MaxSetupCount = 0;
3933 pSMB->Reserved = 0;
3934
3935 param_count = 8;
3936 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3937 data_count = acllen;
3938 data_offset = param_offset + param_count;
3939 byte_count = 3 /* pad */ + param_count;
3940
3941 pSMB->DataCount = cpu_to_le32(data_count);
3942 pSMB->TotalDataCount = pSMB->DataCount;
3943 pSMB->MaxParameterCount = cpu_to_le32(4);
3944 pSMB->MaxDataCount = cpu_to_le32(16384);
3945 pSMB->ParameterCount = cpu_to_le32(param_count);
3946 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3947 pSMB->TotalParameterCount = pSMB->ParameterCount;
3948 pSMB->DataOffset = cpu_to_le32(data_offset);
3949 pSMB->SetupCount = 0;
3950 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3951 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3952
3953 pSMB->Fid = fid; /* file handle always le */
3954 pSMB->Reserved2 = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003955 pSMB->AclFlags = cpu_to_le32(aclflag);
Steve French97837582007-12-31 07:47:21 +00003956
3957 if (pntsd && acllen) {
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003958 memcpy((char *)pSMBr + offsetof(struct smb_hdr, Protocol) +
3959 data_offset, pntsd, acllen);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003960 inc_rfc1001_len(pSMB, byte_count + data_count);
Steve French97837582007-12-31 07:47:21 +00003961 } else
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003962 inc_rfc1001_len(pSMB, byte_count);
Steve French97837582007-12-31 07:47:21 +00003963
3964 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3965 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3966
Joe Perchesb6b38f72010-04-21 03:50:45 +00003967 cFYI(1, "SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00003968 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003969 cFYI(1, "Set CIFS ACL returned %d", rc);
Steve French97837582007-12-31 07:47:21 +00003970 cifs_buf_release(pSMB);
3971
3972 if (rc == -EAGAIN)
3973 goto setCifsAclRetry;
3974
3975 return (rc);
3976}
3977
Jeff Layton79df1ba2010-12-06 12:52:08 -05003978#endif /* CONFIG_CIFS_ACL */
Steve French0a4b92c2006-01-12 15:44:21 -08003979
Steve French6b8edfe2005-08-23 20:26:03 -07003980/* Legacy Query Path Information call for lookup to old servers such
3981 as Win9x/WinME */
Steve French96daf2b2011-05-27 04:34:02 +00003982int SMBQueryInformation(const int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003983 const unsigned char *searchName,
3984 FILE_ALL_INFO *pFinfo,
3985 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003986{
Steve Frenchad7a2922008-02-07 23:25:02 +00003987 QUERY_INFORMATION_REQ *pSMB;
3988 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003989 int rc = 0;
3990 int bytes_returned;
3991 int name_len;
3992
Joe Perchesb6b38f72010-04-21 03:50:45 +00003993 cFYI(1, "In SMBQPath path %s", searchName);
Steve French6b8edfe2005-08-23 20:26:03 -07003994QInfRetry:
3995 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003996 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003997 if (rc)
3998 return rc;
3999
4000 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4001 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004002 cifsConvertToUTF16((__le16 *) pSMB->FileName,
4003 searchName, PATH_MAX, nls_codepage,
4004 remap);
Steve French6b8edfe2005-08-23 20:26:03 -07004005 name_len++; /* trailing null */
4006 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004007 } else {
Steve French6b8edfe2005-08-23 20:26:03 -07004008 name_len = strnlen(searchName, PATH_MAX);
4009 name_len++; /* trailing null */
4010 strncpy(pSMB->FileName, searchName, name_len);
4011 }
4012 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00004013 name_len++; /* account for buffer type byte */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004014 inc_rfc1001_len(pSMB, (__u16)name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07004015 pSMB->ByteCount = cpu_to_le16(name_len);
4016
4017 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004018 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07004019 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004020 cFYI(1, "Send error in QueryInfo = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00004021 } else if (pFinfo) {
Steve French1bd5bbc2006-09-28 03:35:57 +00004022 struct timespec ts;
4023 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00004024
4025 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00004026 /* BB FIXME - add time zone adjustment BB */
Steve French6b8edfe2005-08-23 20:26:03 -07004027 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00004028 ts.tv_nsec = 0;
4029 ts.tv_sec = time;
4030 /* decode time fields */
Al Viro733f99a2006-10-14 16:48:26 +01004031 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
Steve French1bd5bbc2006-09-28 03:35:57 +00004032 pFinfo->LastWriteTime = pFinfo->ChangeTime;
4033 pFinfo->LastAccessTime = 0;
Steve French70ca7342005-09-22 16:32:06 -07004034 pFinfo->AllocationSize =
4035 cpu_to_le64(le32_to_cpu(pSMBr->size));
4036 pFinfo->EndOfFile = pFinfo->AllocationSize;
4037 pFinfo->Attributes =
4038 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07004039 } else
4040 rc = -EIO; /* bad buffer passed in */
4041
4042 cifs_buf_release(pSMB);
4043
4044 if (rc == -EAGAIN)
4045 goto QInfRetry;
4046
4047 return rc;
4048}
4049
Jeff Laytonbcd53572010-02-12 07:44:16 -05004050int
Steve French96daf2b2011-05-27 04:34:02 +00004051CIFSSMBQFileInfo(const int xid, struct cifs_tcon *tcon,
Jeff Laytonbcd53572010-02-12 07:44:16 -05004052 u16 netfid, FILE_ALL_INFO *pFindData)
4053{
4054 struct smb_t2_qfi_req *pSMB = NULL;
4055 struct smb_t2_qfi_rsp *pSMBr = NULL;
4056 int rc = 0;
4057 int bytes_returned;
4058 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07004059
Jeff Laytonbcd53572010-02-12 07:44:16 -05004060QFileInfoRetry:
4061 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4062 (void **) &pSMBr);
4063 if (rc)
4064 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07004065
Jeff Laytonbcd53572010-02-12 07:44:16 -05004066 params = 2 /* level */ + 2 /* fid */;
4067 pSMB->t2.TotalDataCount = 0;
4068 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4069 /* BB find exact max data count below from sess structure BB */
4070 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4071 pSMB->t2.MaxSetupCount = 0;
4072 pSMB->t2.Reserved = 0;
4073 pSMB->t2.Flags = 0;
4074 pSMB->t2.Timeout = 0;
4075 pSMB->t2.Reserved2 = 0;
4076 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4077 Fid) - 4);
4078 pSMB->t2.DataCount = 0;
4079 pSMB->t2.DataOffset = 0;
4080 pSMB->t2.SetupCount = 1;
4081 pSMB->t2.Reserved3 = 0;
4082 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4083 byte_count = params + 1 /* pad */ ;
4084 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4085 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4086 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
4087 pSMB->Pad = 0;
4088 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004089 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonbcd53572010-02-12 07:44:16 -05004090
4091 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4092 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4093 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00004094 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05004095 } else { /* decode response */
4096 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4097
4098 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4099 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004100 else if (get_bcc(&pSMBr->hdr) < 40)
Jeff Laytonbcd53572010-02-12 07:44:16 -05004101 rc = -EIO; /* bad smb */
4102 else if (pFindData) {
4103 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4104 memcpy((char *) pFindData,
4105 (char *) &pSMBr->hdr.Protocol +
4106 data_offset, sizeof(FILE_ALL_INFO));
4107 } else
4108 rc = -ENOMEM;
4109 }
4110 cifs_buf_release(pSMB);
4111 if (rc == -EAGAIN)
4112 goto QFileInfoRetry;
4113
4114 return rc;
4115}
Steve French6b8edfe2005-08-23 20:26:03 -07004116
Linus Torvalds1da177e2005-04-16 15:20:36 -07004117int
Steve French96daf2b2011-05-27 04:34:02 +00004118CIFSSMBQPathInfo(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004119 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00004120 FILE_ALL_INFO *pFindData,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004121 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07004122 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004123{
4124/* level 263 SMB_QUERY_FILE_ALL_INFO */
4125 TRANSACTION2_QPI_REQ *pSMB = NULL;
4126 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4127 int rc = 0;
4128 int bytes_returned;
4129 int name_len;
4130 __u16 params, byte_count;
4131
Joe Perchesb6b38f72010-04-21 03:50:45 +00004132/* cFYI(1, "In QPathInfo path %s", searchName); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004133QPathInfoRetry:
4134 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4135 (void **) &pSMBr);
4136 if (rc)
4137 return rc;
4138
4139 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4140 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004141 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4142 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004143 name_len++; /* trailing null */
4144 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004145 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004146 name_len = strnlen(searchName, PATH_MAX);
4147 name_len++; /* trailing null */
4148 strncpy(pSMB->FileName, searchName, name_len);
4149 }
4150
Steve French50c2f752007-07-13 00:33:32 +00004151 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004152 pSMB->TotalDataCount = 0;
4153 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004154 /* BB find exact max SMB PDU from sess structure BB */
4155 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004156 pSMB->MaxSetupCount = 0;
4157 pSMB->Reserved = 0;
4158 pSMB->Flags = 0;
4159 pSMB->Timeout = 0;
4160 pSMB->Reserved2 = 0;
4161 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004162 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004163 pSMB->DataCount = 0;
4164 pSMB->DataOffset = 0;
4165 pSMB->SetupCount = 1;
4166 pSMB->Reserved3 = 0;
4167 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4168 byte_count = params + 1 /* pad */ ;
4169 pSMB->TotalParameterCount = cpu_to_le16(params);
4170 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00004171 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004172 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
4173 else
4174 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004175 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004176 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004177 pSMB->ByteCount = cpu_to_le16(byte_count);
4178
4179 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4180 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4181 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004182 cFYI(1, "Send error in QPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004183 } else { /* decode response */
4184 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4185
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004186 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4187 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004188 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004189 rc = -EIO; /* bad smb */
Jeff Layton820a8032011-05-04 08:05:26 -04004190 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
Steve French50c2f752007-07-13 00:33:32 +00004191 rc = -EIO; /* 24 or 26 expected but we do not read
4192 last field */
4193 else if (pFindData) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004194 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004195 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00004196
4197 /* On legacy responses we do not read the last field,
4198 EAsize, fortunately since it varies by subdialect and
4199 also note it differs on Set vs. Get, ie two bytes or 4
4200 bytes depending but we don't care here */
4201 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004202 size = sizeof(FILE_INFO_STANDARD);
4203 else
4204 size = sizeof(FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004205 memcpy((char *) pFindData,
4206 (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004207 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004208 } else
4209 rc = -ENOMEM;
4210 }
4211 cifs_buf_release(pSMB);
4212 if (rc == -EAGAIN)
4213 goto QPathInfoRetry;
4214
4215 return rc;
4216}
4217
4218int
Steve French96daf2b2011-05-27 04:34:02 +00004219CIFSSMBUnixQFileInfo(const int xid, struct cifs_tcon *tcon,
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004220 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
4221{
4222 struct smb_t2_qfi_req *pSMB = NULL;
4223 struct smb_t2_qfi_rsp *pSMBr = NULL;
4224 int rc = 0;
4225 int bytes_returned;
4226 __u16 params, byte_count;
4227
4228UnixQFileInfoRetry:
4229 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4230 (void **) &pSMBr);
4231 if (rc)
4232 return rc;
4233
4234 params = 2 /* level */ + 2 /* fid */;
4235 pSMB->t2.TotalDataCount = 0;
4236 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4237 /* BB find exact max data count below from sess structure BB */
4238 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4239 pSMB->t2.MaxSetupCount = 0;
4240 pSMB->t2.Reserved = 0;
4241 pSMB->t2.Flags = 0;
4242 pSMB->t2.Timeout = 0;
4243 pSMB->t2.Reserved2 = 0;
4244 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4245 Fid) - 4);
4246 pSMB->t2.DataCount = 0;
4247 pSMB->t2.DataOffset = 0;
4248 pSMB->t2.SetupCount = 1;
4249 pSMB->t2.Reserved3 = 0;
4250 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4251 byte_count = params + 1 /* pad */ ;
4252 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4253 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4254 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4255 pSMB->Pad = 0;
4256 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004257 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004258
4259 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4260 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4261 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00004262 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004263 } else { /* decode response */
4264 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4265
Jeff Layton820a8032011-05-04 08:05:26 -04004266 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Steve Frenchf19159d2010-04-21 04:12:10 +00004267 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response.\n"
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004268 "Unix Extensions can be disabled on mount "
Steve Frenchf19159d2010-04-21 04:12:10 +00004269 "by specifying the nosfu mount option.");
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004270 rc = -EIO; /* bad smb */
4271 } else {
4272 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4273 memcpy((char *) pFindData,
4274 (char *) &pSMBr->hdr.Protocol +
4275 data_offset,
4276 sizeof(FILE_UNIX_BASIC_INFO));
4277 }
4278 }
4279
4280 cifs_buf_release(pSMB);
4281 if (rc == -EAGAIN)
4282 goto UnixQFileInfoRetry;
4283
4284 return rc;
4285}
4286
4287int
Steve French96daf2b2011-05-27 04:34:02 +00004288CIFSSMBUnixQPathInfo(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004289 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00004290 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07004291 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004292{
4293/* SMB_QUERY_FILE_UNIX_BASIC */
4294 TRANSACTION2_QPI_REQ *pSMB = NULL;
4295 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4296 int rc = 0;
4297 int bytes_returned = 0;
4298 int name_len;
4299 __u16 params, byte_count;
4300
Joe Perchesb6b38f72010-04-21 03:50:45 +00004301 cFYI(1, "In QPathInfo (Unix) the path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004302UnixQPathInfoRetry:
4303 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4304 (void **) &pSMBr);
4305 if (rc)
4306 return rc;
4307
4308 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4309 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004310 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4311 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004312 name_len++; /* trailing null */
4313 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004314 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004315 name_len = strnlen(searchName, PATH_MAX);
4316 name_len++; /* trailing null */
4317 strncpy(pSMB->FileName, searchName, name_len);
4318 }
4319
Steve French50c2f752007-07-13 00:33:32 +00004320 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004321 pSMB->TotalDataCount = 0;
4322 pSMB->MaxParameterCount = cpu_to_le16(2);
4323 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00004324 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004325 pSMB->MaxSetupCount = 0;
4326 pSMB->Reserved = 0;
4327 pSMB->Flags = 0;
4328 pSMB->Timeout = 0;
4329 pSMB->Reserved2 = 0;
4330 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004331 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004332 pSMB->DataCount = 0;
4333 pSMB->DataOffset = 0;
4334 pSMB->SetupCount = 1;
4335 pSMB->Reserved3 = 0;
4336 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4337 byte_count = params + 1 /* pad */ ;
4338 pSMB->TotalParameterCount = cpu_to_le16(params);
4339 pSMB->ParameterCount = pSMB->TotalParameterCount;
4340 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4341 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004342 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004343 pSMB->ByteCount = cpu_to_le16(byte_count);
4344
4345 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4346 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4347 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004348 cFYI(1, "Send error in QPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004349 } else { /* decode response */
4350 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4351
Jeff Layton820a8032011-05-04 08:05:26 -04004352 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004353 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response.\n"
Steve French1e71f252007-09-20 15:30:07 +00004354 "Unix Extensions can be disabled on mount "
Joe Perchesb6b38f72010-04-21 03:50:45 +00004355 "by specifying the nosfu mount option.");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004356 rc = -EIO; /* bad smb */
4357 } else {
4358 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4359 memcpy((char *) pFindData,
4360 (char *) &pSMBr->hdr.Protocol +
4361 data_offset,
Steve French630f3f02007-10-25 21:17:17 +00004362 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004363 }
4364 }
4365 cifs_buf_release(pSMB);
4366 if (rc == -EAGAIN)
4367 goto UnixQPathInfoRetry;
4368
4369 return rc;
4370}
4371
Linus Torvalds1da177e2005-04-16 15:20:36 -07004372/* xid, tcon, searchName and codepage are input parms, rest are returned */
4373int
Steve French96daf2b2011-05-27 04:34:02 +00004374CIFSFindFirst(const int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004375 const char *searchName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004376 const struct nls_table *nls_codepage,
Shirish Pargaonkar444b7bc2012-05-15 10:19:16 -05004377 __u16 *pnetfid, __u16 search_flags,
Steve French50c2f752007-07-13 00:33:32 +00004378 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004379{
4380/* level 257 SMB_ */
4381 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
4382 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004383 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004384 int rc = 0;
4385 int bytes_returned = 0;
4386 int name_len;
4387 __u16 params, byte_count;
4388
Joe Perchesb6b38f72010-04-21 03:50:45 +00004389 cFYI(1, "In FindFirst for %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004390
4391findFirstRetry:
4392 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4393 (void **) &pSMBr);
4394 if (rc)
4395 return rc;
4396
4397 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4398 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004399 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4400 PATH_MAX, nls_codepage, remap);
Steve French737b7582005-04-28 22:41:06 -07004401 /* We can not add the asterik earlier in case
4402 it got remapped to 0xF03A as if it were part of the
4403 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004404 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07004405 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07004406 pSMB->FileName[name_len+1] = 0;
4407 pSMB->FileName[name_len+2] = '*';
4408 pSMB->FileName[name_len+3] = 0;
4409 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004410 pSMB->FileName[name_len] = 0; /* null terminate just in case */
4411 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07004412 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004413 } else { /* BB add check for overrun of SMB buf BB */
4414 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004415/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00004416 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004417 free buffer exit; BB */
4418 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07004419 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07004420 pSMB->FileName[name_len+1] = '*';
4421 pSMB->FileName[name_len+2] = 0;
4422 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004423 }
4424
4425 params = 12 + name_len /* includes null */ ;
4426 pSMB->TotalDataCount = 0; /* no EAs */
4427 pSMB->MaxParameterCount = cpu_to_le16(10);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004428 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004429 pSMB->MaxSetupCount = 0;
4430 pSMB->Reserved = 0;
4431 pSMB->Flags = 0;
4432 pSMB->Timeout = 0;
4433 pSMB->Reserved2 = 0;
4434 byte_count = params + 1 /* pad */ ;
4435 pSMB->TotalParameterCount = cpu_to_le16(params);
4436 pSMB->ParameterCount = pSMB->TotalParameterCount;
4437 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00004438 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
4439 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004440 pSMB->DataCount = 0;
4441 pSMB->DataOffset = 0;
4442 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
4443 pSMB->Reserved3 = 0;
4444 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
4445 pSMB->SearchAttributes =
4446 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
4447 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00004448 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
Shirish Pargaonkar444b7bc2012-05-15 10:19:16 -05004449 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004450 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4451
4452 /* BB what should we set StorageType to? Does it matter? BB */
4453 pSMB->SearchStorageType = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004454 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004455 pSMB->ByteCount = cpu_to_le16(byte_count);
4456
4457 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4458 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07004459 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004460
Steve French88274812006-03-09 22:21:45 +00004461 if (rc) {/* BB add logic to retry regular search if Unix search
4462 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004463 /* BB Add code to handle unsupported level rc */
Joe Perchesb6b38f72010-04-21 03:50:45 +00004464 cFYI(1, "Error in FindFirst = %d", rc);
Steve French1982c342005-08-17 12:38:22 -07004465
Steve French88274812006-03-09 22:21:45 +00004466 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004467
4468 /* BB eventually could optimize out free and realloc of buf */
4469 /* for this case */
4470 if (rc == -EAGAIN)
4471 goto findFirstRetry;
4472 } else { /* decode response */
4473 /* BB remember to free buffer if error BB */
4474 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00004475 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004476 unsigned int lnoff;
4477
Linus Torvalds1da177e2005-04-16 15:20:36 -07004478 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004479 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004480 else
Steve French4b18f2a2008-04-29 00:06:05 +00004481 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004482
4483 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004484 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00004485 psrch_inf->srch_entries_start =
4486 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004487 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004488 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
4489 le16_to_cpu(pSMBr->t2.ParameterOffset));
4490
Steve French790fe572007-07-07 19:25:05 +00004491 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004492 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004493 else
Steve French4b18f2a2008-04-29 00:06:05 +00004494 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004495
Steve French50c2f752007-07-13 00:33:32 +00004496 psrch_inf->entries_in_buffer =
4497 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00004498 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004499 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004500 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004501 if (CIFSMaxBufSize < lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004502 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00004503 psrch_inf->last_entry = NULL;
4504 return rc;
4505 }
4506
Steve French0752f152008-10-07 20:03:33 +00004507 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00004508 lnoff;
4509
Linus Torvalds1da177e2005-04-16 15:20:36 -07004510 *pnetfid = parms->SearchHandle;
4511 } else {
4512 cifs_buf_release(pSMB);
4513 }
4514 }
4515
4516 return rc;
4517}
4518
Shirish Pargaonkar444b7bc2012-05-15 10:19:16 -05004519int CIFSFindNext(const int xid, struct cifs_tcon *tcon, __u16 searchHandle,
4520 __u16 search_flags, struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004521{
4522 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
4523 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004524 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004525 char *response_data;
4526 int rc = 0;
Jeff Layton9438fab2011-08-23 07:21:28 -04004527 int bytes_returned;
4528 unsigned int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004529 __u16 params, byte_count;
4530
Joe Perchesb6b38f72010-04-21 03:50:45 +00004531 cFYI(1, "In FindNext");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004532
Steve French4b18f2a2008-04-29 00:06:05 +00004533 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004534 return -ENOENT;
4535
4536 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4537 (void **) &pSMBr);
4538 if (rc)
4539 return rc;
4540
Steve French50c2f752007-07-13 00:33:32 +00004541 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004542 byte_count = 0;
4543 pSMB->TotalDataCount = 0; /* no EAs */
4544 pSMB->MaxParameterCount = cpu_to_le16(8);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004545 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004546 pSMB->MaxSetupCount = 0;
4547 pSMB->Reserved = 0;
4548 pSMB->Flags = 0;
4549 pSMB->Timeout = 0;
4550 pSMB->Reserved2 = 0;
4551 pSMB->ParameterOffset = cpu_to_le16(
4552 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
4553 pSMB->DataCount = 0;
4554 pSMB->DataOffset = 0;
4555 pSMB->SetupCount = 1;
4556 pSMB->Reserved3 = 0;
4557 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
4558 pSMB->SearchHandle = searchHandle; /* always kept as le */
4559 pSMB->SearchCount =
Steve French630f3f02007-10-25 21:17:17 +00004560 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004561 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4562 pSMB->ResumeKey = psrch_inf->resume_key;
Shirish Pargaonkar444b7bc2012-05-15 10:19:16 -05004563 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004564
4565 name_len = psrch_inf->resume_name_len;
4566 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00004567 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004568 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
4569 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07004570 /* 14 byte parm len above enough for 2 byte null terminator */
4571 pSMB->ResumeFileName[name_len] = 0;
4572 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004573 } else {
4574 rc = -EINVAL;
4575 goto FNext2_err_exit;
4576 }
4577 byte_count = params + 1 /* pad */ ;
4578 pSMB->TotalParameterCount = cpu_to_le16(params);
4579 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004580 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004581 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004582
Linus Torvalds1da177e2005-04-16 15:20:36 -07004583 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4584 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07004585 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004586 if (rc) {
4587 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00004588 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07004589 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00004590 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004591 } else
Joe Perchesb6b38f72010-04-21 03:50:45 +00004592 cFYI(1, "FindNext returned = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004593 } else { /* decode response */
4594 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00004595
Steve French790fe572007-07-07 19:25:05 +00004596 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004597 unsigned int lnoff;
4598
Linus Torvalds1da177e2005-04-16 15:20:36 -07004599 /* BB fixme add lock for file (srch_info) struct here */
4600 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004601 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004602 else
Steve French4b18f2a2008-04-29 00:06:05 +00004603 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004604 response_data = (char *) &pSMBr->hdr.Protocol +
4605 le16_to_cpu(pSMBr->t2.ParameterOffset);
4606 parms = (T2_FNEXT_RSP_PARMS *)response_data;
4607 response_data = (char *)&pSMBr->hdr.Protocol +
4608 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00004609 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00004610 cifs_small_buf_release(
4611 psrch_inf->ntwrk_buf_start);
4612 else
4613 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004614 psrch_inf->srch_entries_start = response_data;
4615 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004616 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00004617 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004618 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004619 else
Steve French4b18f2a2008-04-29 00:06:05 +00004620 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00004621 psrch_inf->entries_in_buffer =
4622 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004623 psrch_inf->index_of_last_entry +=
4624 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004625 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004626 if (CIFSMaxBufSize < lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004627 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00004628 psrch_inf->last_entry = NULL;
4629 return rc;
4630 } else
4631 psrch_inf->last_entry =
4632 psrch_inf->srch_entries_start + lnoff;
4633
Joe Perchesb6b38f72010-04-21 03:50:45 +00004634/* cFYI(1, "fnxt2 entries in buf %d index_of_last %d",
4635 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004636
4637 /* BB fixme add unlock here */
4638 }
4639
4640 }
4641
4642 /* BB On error, should we leave previous search buf (and count and
4643 last entry fields) intact or free the previous one? */
4644
4645 /* Note: On -EAGAIN error only caller can retry on handle based calls
4646 since file handle passed in no longer valid */
4647FNext2_err_exit:
4648 if (rc != 0)
4649 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004650 return rc;
4651}
4652
4653int
Steve French96daf2b2011-05-27 04:34:02 +00004654CIFSFindClose(const int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004655 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004656{
4657 int rc = 0;
4658 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004659
Joe Perchesb6b38f72010-04-21 03:50:45 +00004660 cFYI(1, "In CIFSSMBFindClose");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004661 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
4662
4663 /* no sense returning error if session restarted
4664 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00004665 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004666 return 0;
4667 if (rc)
4668 return rc;
4669
Linus Torvalds1da177e2005-04-16 15:20:36 -07004670 pSMB->FileID = searchHandle;
4671 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04004672 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004673 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00004674 cERROR(1, "Send error in FindClose = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00004675
Steve Frencha4544342005-08-24 13:59:35 -07004676 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004677
4678 /* Since session is dead, search handle closed on server already */
4679 if (rc == -EAGAIN)
4680 rc = 0;
4681
4682 return rc;
4683}
4684
Linus Torvalds1da177e2005-04-16 15:20:36 -07004685int
Steve French96daf2b2011-05-27 04:34:02 +00004686CIFSGetSrvInodeNumber(const int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004687 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00004688 __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00004689 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004690{
4691 int rc = 0;
4692 TRANSACTION2_QPI_REQ *pSMB = NULL;
4693 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4694 int name_len, bytes_returned;
4695 __u16 params, byte_count;
4696
Joe Perchesb6b38f72010-04-21 03:50:45 +00004697 cFYI(1, "In GetSrvInodeNum for %s", searchName);
Steve French790fe572007-07-07 19:25:05 +00004698 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00004699 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004700
4701GetInodeNumberRetry:
4702 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004703 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004704 if (rc)
4705 return rc;
4706
Linus Torvalds1da177e2005-04-16 15:20:36 -07004707 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4708 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004709 cifsConvertToUTF16((__le16 *) pSMB->FileName,
4710 searchName, PATH_MAX, nls_codepage,
4711 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004712 name_len++; /* trailing null */
4713 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004714 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004715 name_len = strnlen(searchName, PATH_MAX);
4716 name_len++; /* trailing null */
4717 strncpy(pSMB->FileName, searchName, name_len);
4718 }
4719
4720 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4721 pSMB->TotalDataCount = 0;
4722 pSMB->MaxParameterCount = cpu_to_le16(2);
4723 /* BB find exact max data count below from sess structure BB */
4724 pSMB->MaxDataCount = cpu_to_le16(4000);
4725 pSMB->MaxSetupCount = 0;
4726 pSMB->Reserved = 0;
4727 pSMB->Flags = 0;
4728 pSMB->Timeout = 0;
4729 pSMB->Reserved2 = 0;
4730 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004731 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004732 pSMB->DataCount = 0;
4733 pSMB->DataOffset = 0;
4734 pSMB->SetupCount = 1;
4735 pSMB->Reserved3 = 0;
4736 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4737 byte_count = params + 1 /* pad */ ;
4738 pSMB->TotalParameterCount = cpu_to_le16(params);
4739 pSMB->ParameterCount = pSMB->TotalParameterCount;
4740 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4741 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004742 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004743 pSMB->ByteCount = cpu_to_le16(byte_count);
4744
4745 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4746 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4747 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004748 cFYI(1, "error %d in QueryInternalInfo", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004749 } else {
4750 /* decode response */
4751 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004752 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04004753 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004754 /* If rc should we check for EOPNOSUPP and
4755 disable the srvino flag? or in caller? */
4756 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00004757 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004758 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4759 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00004760 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004761 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00004762 if (count < 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004763 cFYI(1, "Illegal size ret in QryIntrnlInf");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004764 rc = -EIO;
4765 goto GetInodeNumOut;
4766 }
4767 pfinfo = (struct file_internal_info *)
4768 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00004769 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004770 }
4771 }
4772GetInodeNumOut:
4773 cifs_buf_release(pSMB);
4774 if (rc == -EAGAIN)
4775 goto GetInodeNumberRetry;
4776 return rc;
4777}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004778
Igor Mammedovfec45852008-05-16 13:06:30 +04004779/* parses DFS refferal V3 structure
4780 * caller is responsible for freeing target_nodes
4781 * returns:
4782 * on success - 0
4783 * on failure - errno
4784 */
4785static int
Steve Frencha1fe78f2008-05-16 18:48:38 +00004786parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
Igor Mammedovfec45852008-05-16 13:06:30 +04004787 unsigned int *num_of_nodes,
4788 struct dfs_info3_param **target_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004789 const struct nls_table *nls_codepage, int remap,
4790 const char *searchName)
Igor Mammedovfec45852008-05-16 13:06:30 +04004791{
4792 int i, rc = 0;
4793 char *data_end;
4794 bool is_unicode;
4795 struct dfs_referral_level_3 *ref;
4796
Harvey Harrison5ca33c62008-07-23 17:45:58 -07004797 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4798 is_unicode = true;
4799 else
4800 is_unicode = false;
Igor Mammedovfec45852008-05-16 13:06:30 +04004801 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
4802
4803 if (*num_of_nodes < 1) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004804 cERROR(1, "num_referrals: must be at least > 0,"
4805 "but we get num_referrals = %d\n", *num_of_nodes);
Igor Mammedovfec45852008-05-16 13:06:30 +04004806 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004807 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004808 }
4809
4810 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
Al Viro1d92cfd2008-06-02 10:59:02 +01004811 if (ref->VersionNumber != cpu_to_le16(3)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004812 cERROR(1, "Referrals of V%d version are not supported,"
4813 "should be V3", le16_to_cpu(ref->VersionNumber));
Igor Mammedovfec45852008-05-16 13:06:30 +04004814 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004815 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004816 }
4817
4818 /* get the upper boundary of the resp buffer */
4819 data_end = (char *)(&(pSMBr->PathConsumed)) +
4820 le16_to_cpu(pSMBr->t2.DataCount);
4821
Steve Frenchf19159d2010-04-21 04:12:10 +00004822 cFYI(1, "num_referrals: %d dfs flags: 0x%x ...\n",
Igor Mammedovfec45852008-05-16 13:06:30 +04004823 *num_of_nodes,
Joe Perchesb6b38f72010-04-21 03:50:45 +00004824 le32_to_cpu(pSMBr->DFSFlags));
Igor Mammedovfec45852008-05-16 13:06:30 +04004825
4826 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
4827 *num_of_nodes, GFP_KERNEL);
4828 if (*target_nodes == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004829 cERROR(1, "Failed to allocate buffer for target_nodes\n");
Igor Mammedovfec45852008-05-16 13:06:30 +04004830 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004831 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004832 }
4833
Daniel Mack3ad2f3f2010-02-03 08:01:28 +08004834 /* collect necessary data from referrals */
Igor Mammedovfec45852008-05-16 13:06:30 +04004835 for (i = 0; i < *num_of_nodes; i++) {
4836 char *temp;
4837 int max_len;
4838 struct dfs_info3_param *node = (*target_nodes)+i;
4839
Steve French0e0d2cf2009-05-01 05:27:32 +00004840 node->flags = le32_to_cpu(pSMBr->DFSFlags);
Igor Mammedov2c556082008-10-23 13:58:42 +04004841 if (is_unicode) {
Jeff Layton331c3132008-12-17 06:31:53 -05004842 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4843 GFP_KERNEL);
Steve French2920ee22009-08-31 15:27:26 +00004844 if (tmp == NULL) {
4845 rc = -ENOMEM;
4846 goto parse_DFS_referrals_exit;
4847 }
Steve Frenchacbbb762012-01-18 22:32:33 -06004848 cifsConvertToUTF16((__le16 *) tmp, searchName,
4849 PATH_MAX, nls_codepage, remap);
4850 node->path_consumed = cifs_utf16_bytes(tmp,
Jeff Layton69f801f2009-04-30 06:46:32 -04004851 le16_to_cpu(pSMBr->PathConsumed),
Igor Mammedov2c556082008-10-23 13:58:42 +04004852 nls_codepage);
4853 kfree(tmp);
4854 } else
4855 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4856
Igor Mammedovfec45852008-05-16 13:06:30 +04004857 node->server_type = le16_to_cpu(ref->ServerType);
4858 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4859
4860 /* copy DfsPath */
4861 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4862 max_len = data_end - temp;
Steve Frenchacbbb762012-01-18 22:32:33 -06004863 node->path_name = cifs_strndup_from_utf16(temp, max_len,
4864 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004865 if (!node->path_name) {
4866 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004867 goto parse_DFS_referrals_exit;
Jeff Layton066ce682009-04-30 07:16:14 -04004868 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004869
4870 /* copy link target UNC */
4871 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4872 max_len = data_end - temp;
Steve Frenchacbbb762012-01-18 22:32:33 -06004873 node->node_name = cifs_strndup_from_utf16(temp, max_len,
4874 is_unicode, nls_codepage);
Stefan Metzmacherd8f27992012-05-04 00:19:28 +02004875 if (!node->node_name) {
Jeff Laytond8e2f532009-05-14 07:46:59 -04004876 rc = -ENOMEM;
Stefan Metzmacherd8f27992012-05-04 00:19:28 +02004877 goto parse_DFS_referrals_exit;
4878 }
4879
4880 ref++;
Igor Mammedovfec45852008-05-16 13:06:30 +04004881 }
4882
Steve Frencha1fe78f2008-05-16 18:48:38 +00004883parse_DFS_referrals_exit:
Igor Mammedovfec45852008-05-16 13:06:30 +04004884 if (rc) {
4885 free_dfs_info_array(*target_nodes, *num_of_nodes);
4886 *target_nodes = NULL;
4887 *num_of_nodes = 0;
4888 }
4889 return rc;
4890}
4891
Linus Torvalds1da177e2005-04-16 15:20:36 -07004892int
Steve French96daf2b2011-05-27 04:34:02 +00004893CIFSGetDFSRefer(const int xid, struct cifs_ses *ses,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004894 const unsigned char *searchName,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004895 struct dfs_info3_param **target_nodes,
4896 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004897 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004898{
4899/* TRANS2_GET_DFS_REFERRAL */
4900 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4901 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004902 int rc = 0;
4903 int bytes_returned;
4904 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004905 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004906 *num_of_nodes = 0;
4907 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004908
Joe Perchesb6b38f72010-04-21 03:50:45 +00004909 cFYI(1, "In GetDFSRefer the path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004910 if (ses == NULL)
4911 return -ENODEV;
4912getDFSRetry:
4913 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4914 (void **) &pSMBr);
4915 if (rc)
4916 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004917
4918 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004919 but should never be null here anyway */
4920 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004921 pSMB->hdr.Tid = ses->ipc_tid;
4922 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004923 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004924 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004925 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004926 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004927
4928 if (ses->capabilities & CAP_UNICODE) {
4929 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4930 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004931 cifsConvertToUTF16((__le16 *) pSMB->RequestFileName,
4932 searchName, PATH_MAX, nls_codepage,
4933 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004934 name_len++; /* trailing null */
4935 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004936 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004937 name_len = strnlen(searchName, PATH_MAX);
4938 name_len++; /* trailing null */
4939 strncpy(pSMB->RequestFileName, searchName, name_len);
4940 }
4941
Steve French790fe572007-07-07 19:25:05 +00004942 if (ses->server) {
Steve French96daf2b2011-05-27 04:34:02 +00004943 if (ses->server->sec_mode &
Steve French1a4e15a2006-10-12 21:33:51 +00004944 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4945 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4946 }
4947
Steve French50c2f752007-07-13 00:33:32 +00004948 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004949
Linus Torvalds1da177e2005-04-16 15:20:36 -07004950 params = 2 /* level */ + name_len /*includes null */ ;
4951 pSMB->TotalDataCount = 0;
4952 pSMB->DataCount = 0;
4953 pSMB->DataOffset = 0;
4954 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004955 /* BB find exact max SMB PDU from sess structure BB */
4956 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004957 pSMB->MaxSetupCount = 0;
4958 pSMB->Reserved = 0;
4959 pSMB->Flags = 0;
4960 pSMB->Timeout = 0;
4961 pSMB->Reserved2 = 0;
4962 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004963 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004964 pSMB->SetupCount = 1;
4965 pSMB->Reserved3 = 0;
4966 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4967 byte_count = params + 3 /* pad */ ;
4968 pSMB->ParameterCount = cpu_to_le16(params);
4969 pSMB->TotalParameterCount = pSMB->ParameterCount;
4970 pSMB->MaxReferralLevel = cpu_to_le16(3);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004971 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004972 pSMB->ByteCount = cpu_to_le16(byte_count);
4973
4974 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4975 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4976 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004977 cFYI(1, "Send error in GetDFSRefer = %d", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004978 goto GetDFSRefExit;
4979 }
4980 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004981
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004982 /* BB Also check if enough total bytes returned? */
Jeff Layton820a8032011-05-04 08:05:26 -04004983 if (rc || get_bcc(&pSMBr->hdr) < 17) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004984 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004985 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004986 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004987
Joe Perchesb6b38f72010-04-21 03:50:45 +00004988 cFYI(1, "Decoding GetDFSRefer response BCC: %d Offset %d",
Jeff Layton820a8032011-05-04 08:05:26 -04004989 get_bcc(&pSMBr->hdr),
Joe Perchesb6b38f72010-04-21 03:50:45 +00004990 le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04004991
4992 /* parse returned result into more usable form */
Steve Frencha1fe78f2008-05-16 18:48:38 +00004993 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004994 target_nodes, nls_codepage, remap,
4995 searchName);
Igor Mammedovfec45852008-05-16 13:06:30 +04004996
Linus Torvalds1da177e2005-04-16 15:20:36 -07004997GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004998 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004999
5000 if (rc == -EAGAIN)
5001 goto getDFSRetry;
5002
5003 return rc;
5004}
5005
Steve French20962432005-09-21 22:05:57 -07005006/* Query File System Info such as free space to old servers such as Win 9x */
5007int
Steve French96daf2b2011-05-27 04:34:02 +00005008SMBOldQFSInfo(const int xid, struct cifs_tcon *tcon, struct kstatfs *FSData)
Steve French20962432005-09-21 22:05:57 -07005009{
5010/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
5011 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5012 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5013 FILE_SYSTEM_ALLOC_INFO *response_data;
5014 int rc = 0;
5015 int bytes_returned = 0;
5016 __u16 params, byte_count;
5017
Joe Perchesb6b38f72010-04-21 03:50:45 +00005018 cFYI(1, "OldQFSInfo");
Steve French20962432005-09-21 22:05:57 -07005019oldQFSInfoRetry:
5020 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5021 (void **) &pSMBr);
5022 if (rc)
5023 return rc;
Steve French20962432005-09-21 22:05:57 -07005024
5025 params = 2; /* level */
5026 pSMB->TotalDataCount = 0;
5027 pSMB->MaxParameterCount = cpu_to_le16(2);
5028 pSMB->MaxDataCount = cpu_to_le16(1000);
5029 pSMB->MaxSetupCount = 0;
5030 pSMB->Reserved = 0;
5031 pSMB->Flags = 0;
5032 pSMB->Timeout = 0;
5033 pSMB->Reserved2 = 0;
5034 byte_count = params + 1 /* pad */ ;
5035 pSMB->TotalParameterCount = cpu_to_le16(params);
5036 pSMB->ParameterCount = pSMB->TotalParameterCount;
5037 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5038 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
5039 pSMB->DataCount = 0;
5040 pSMB->DataOffset = 0;
5041 pSMB->SetupCount = 1;
5042 pSMB->Reserved3 = 0;
5043 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5044 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005045 inc_rfc1001_len(pSMB, byte_count);
Steve French20962432005-09-21 22:05:57 -07005046 pSMB->ByteCount = cpu_to_le16(byte_count);
5047
5048 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5049 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5050 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005051 cFYI(1, "Send error in QFSInfo = %d", rc);
Steve French20962432005-09-21 22:05:57 -07005052 } else { /* decode response */
5053 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5054
Jeff Layton820a8032011-05-04 08:05:26 -04005055 if (rc || get_bcc(&pSMBr->hdr) < 18)
Steve French20962432005-09-21 22:05:57 -07005056 rc = -EIO; /* bad smb */
5057 else {
5058 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesb6b38f72010-04-21 03:50:45 +00005059 cFYI(1, "qfsinf resp BCC: %d Offset %d",
Jeff Layton820a8032011-05-04 08:05:26 -04005060 get_bcc(&pSMBr->hdr), data_offset);
Steve French20962432005-09-21 22:05:57 -07005061
Steve French50c2f752007-07-13 00:33:32 +00005062 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07005063 (((char *) &pSMBr->hdr.Protocol) + data_offset);
5064 FSData->f_bsize =
5065 le16_to_cpu(response_data->BytesPerSector) *
5066 le32_to_cpu(response_data->
5067 SectorsPerAllocationUnit);
5068 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00005069 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07005070 FSData->f_bfree = FSData->f_bavail =
5071 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesb6b38f72010-04-21 03:50:45 +00005072 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
5073 (unsigned long long)FSData->f_blocks,
5074 (unsigned long long)FSData->f_bfree,
5075 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07005076 }
5077 }
5078 cifs_buf_release(pSMB);
5079
5080 if (rc == -EAGAIN)
5081 goto oldQFSInfoRetry;
5082
5083 return rc;
5084}
5085
Linus Torvalds1da177e2005-04-16 15:20:36 -07005086int
Steve French96daf2b2011-05-27 04:34:02 +00005087CIFSSMBQFSInfo(const int xid, struct cifs_tcon *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005088{
5089/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
5090 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5091 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5092 FILE_SYSTEM_INFO *response_data;
5093 int rc = 0;
5094 int bytes_returned = 0;
5095 __u16 params, byte_count;
5096
Joe Perchesb6b38f72010-04-21 03:50:45 +00005097 cFYI(1, "In QFSInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005098QFSInfoRetry:
5099 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5100 (void **) &pSMBr);
5101 if (rc)
5102 return rc;
5103
5104 params = 2; /* level */
5105 pSMB->TotalDataCount = 0;
5106 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07005107 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005108 pSMB->MaxSetupCount = 0;
5109 pSMB->Reserved = 0;
5110 pSMB->Flags = 0;
5111 pSMB->Timeout = 0;
5112 pSMB->Reserved2 = 0;
5113 byte_count = params + 1 /* pad */ ;
5114 pSMB->TotalParameterCount = cpu_to_le16(params);
5115 pSMB->ParameterCount = pSMB->TotalParameterCount;
5116 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005117 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005118 pSMB->DataCount = 0;
5119 pSMB->DataOffset = 0;
5120 pSMB->SetupCount = 1;
5121 pSMB->Reserved3 = 0;
5122 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5123 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005124 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005125 pSMB->ByteCount = cpu_to_le16(byte_count);
5126
5127 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5128 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5129 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005130 cFYI(1, "Send error in QFSInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005131 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00005132 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005133
Jeff Layton820a8032011-05-04 08:05:26 -04005134 if (rc || get_bcc(&pSMBr->hdr) < 24)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005135 rc = -EIO; /* bad smb */
5136 else {
5137 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005138
5139 response_data =
5140 (FILE_SYSTEM_INFO
5141 *) (((char *) &pSMBr->hdr.Protocol) +
5142 data_offset);
5143 FSData->f_bsize =
5144 le32_to_cpu(response_data->BytesPerSector) *
5145 le32_to_cpu(response_data->
5146 SectorsPerAllocationUnit);
5147 FSData->f_blocks =
5148 le64_to_cpu(response_data->TotalAllocationUnits);
5149 FSData->f_bfree = FSData->f_bavail =
5150 le64_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesb6b38f72010-04-21 03:50:45 +00005151 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
5152 (unsigned long long)FSData->f_blocks,
5153 (unsigned long long)FSData->f_bfree,
5154 FSData->f_bsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005155 }
5156 }
5157 cifs_buf_release(pSMB);
5158
5159 if (rc == -EAGAIN)
5160 goto QFSInfoRetry;
5161
5162 return rc;
5163}
5164
5165int
Steve French96daf2b2011-05-27 04:34:02 +00005166CIFSSMBQFSAttributeInfo(const int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005167{
5168/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
5169 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5170 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5171 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
5172 int rc = 0;
5173 int bytes_returned = 0;
5174 __u16 params, byte_count;
5175
Joe Perchesb6b38f72010-04-21 03:50:45 +00005176 cFYI(1, "In QFSAttributeInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005177QFSAttributeRetry:
5178 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5179 (void **) &pSMBr);
5180 if (rc)
5181 return rc;
5182
5183 params = 2; /* level */
5184 pSMB->TotalDataCount = 0;
5185 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005186 /* BB find exact max SMB PDU from sess structure BB */
5187 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005188 pSMB->MaxSetupCount = 0;
5189 pSMB->Reserved = 0;
5190 pSMB->Flags = 0;
5191 pSMB->Timeout = 0;
5192 pSMB->Reserved2 = 0;
5193 byte_count = params + 1 /* pad */ ;
5194 pSMB->TotalParameterCount = cpu_to_le16(params);
5195 pSMB->ParameterCount = pSMB->TotalParameterCount;
5196 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005197 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005198 pSMB->DataCount = 0;
5199 pSMB->DataOffset = 0;
5200 pSMB->SetupCount = 1;
5201 pSMB->Reserved3 = 0;
5202 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5203 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005204 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005205 pSMB->ByteCount = cpu_to_le16(byte_count);
5206
5207 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5208 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5209 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005210 cERROR(1, "Send error in QFSAttributeInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005211 } else { /* decode response */
5212 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5213
Jeff Layton820a8032011-05-04 08:05:26 -04005214 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Steve French50c2f752007-07-13 00:33:32 +00005215 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005216 rc = -EIO; /* bad smb */
5217 } else {
5218 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5219 response_data =
5220 (FILE_SYSTEM_ATTRIBUTE_INFO
5221 *) (((char *) &pSMBr->hdr.Protocol) +
5222 data_offset);
5223 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005224 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005225 }
5226 }
5227 cifs_buf_release(pSMB);
5228
5229 if (rc == -EAGAIN)
5230 goto QFSAttributeRetry;
5231
5232 return rc;
5233}
5234
5235int
Steve French96daf2b2011-05-27 04:34:02 +00005236CIFSSMBQFSDeviceInfo(const int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005237{
5238/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
5239 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5240 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5241 FILE_SYSTEM_DEVICE_INFO *response_data;
5242 int rc = 0;
5243 int bytes_returned = 0;
5244 __u16 params, byte_count;
5245
Joe Perchesb6b38f72010-04-21 03:50:45 +00005246 cFYI(1, "In QFSDeviceInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005247QFSDeviceRetry:
5248 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5249 (void **) &pSMBr);
5250 if (rc)
5251 return rc;
5252
5253 params = 2; /* level */
5254 pSMB->TotalDataCount = 0;
5255 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005256 /* BB find exact max SMB PDU from sess structure BB */
5257 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005258 pSMB->MaxSetupCount = 0;
5259 pSMB->Reserved = 0;
5260 pSMB->Flags = 0;
5261 pSMB->Timeout = 0;
5262 pSMB->Reserved2 = 0;
5263 byte_count = params + 1 /* pad */ ;
5264 pSMB->TotalParameterCount = cpu_to_le16(params);
5265 pSMB->ParameterCount = pSMB->TotalParameterCount;
5266 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005267 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005268
5269 pSMB->DataCount = 0;
5270 pSMB->DataOffset = 0;
5271 pSMB->SetupCount = 1;
5272 pSMB->Reserved3 = 0;
5273 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5274 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005275 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005276 pSMB->ByteCount = cpu_to_le16(byte_count);
5277
5278 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5279 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5280 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005281 cFYI(1, "Send error in QFSDeviceInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005282 } else { /* decode response */
5283 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5284
Jeff Layton820a8032011-05-04 08:05:26 -04005285 if (rc || get_bcc(&pSMBr->hdr) <
5286 sizeof(FILE_SYSTEM_DEVICE_INFO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005287 rc = -EIO; /* bad smb */
5288 else {
5289 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5290 response_data =
Steve French737b7582005-04-28 22:41:06 -07005291 (FILE_SYSTEM_DEVICE_INFO *)
5292 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07005293 data_offset);
5294 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005295 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005296 }
5297 }
5298 cifs_buf_release(pSMB);
5299
5300 if (rc == -EAGAIN)
5301 goto QFSDeviceRetry;
5302
5303 return rc;
5304}
5305
5306int
Steve French96daf2b2011-05-27 04:34:02 +00005307CIFSSMBQFSUnixInfo(const int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005308{
5309/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
5310 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5311 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5312 FILE_SYSTEM_UNIX_INFO *response_data;
5313 int rc = 0;
5314 int bytes_returned = 0;
5315 __u16 params, byte_count;
5316
Joe Perchesb6b38f72010-04-21 03:50:45 +00005317 cFYI(1, "In QFSUnixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005318QFSUnixRetry:
Jeff Laytonf5695992010-09-29 15:27:08 -04005319 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5320 (void **) &pSMB, (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005321 if (rc)
5322 return rc;
5323
5324 params = 2; /* level */
5325 pSMB->TotalDataCount = 0;
5326 pSMB->DataCount = 0;
5327 pSMB->DataOffset = 0;
5328 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005329 /* BB find exact max SMB PDU from sess structure BB */
5330 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005331 pSMB->MaxSetupCount = 0;
5332 pSMB->Reserved = 0;
5333 pSMB->Flags = 0;
5334 pSMB->Timeout = 0;
5335 pSMB->Reserved2 = 0;
5336 byte_count = params + 1 /* pad */ ;
5337 pSMB->ParameterCount = cpu_to_le16(params);
5338 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005339 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5340 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005341 pSMB->SetupCount = 1;
5342 pSMB->Reserved3 = 0;
5343 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5344 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005345 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005346 pSMB->ByteCount = cpu_to_le16(byte_count);
5347
5348 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5349 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5350 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005351 cERROR(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005352 } else { /* decode response */
5353 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5354
Jeff Layton820a8032011-05-04 08:05:26 -04005355 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005356 rc = -EIO; /* bad smb */
5357 } else {
5358 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5359 response_data =
5360 (FILE_SYSTEM_UNIX_INFO
5361 *) (((char *) &pSMBr->hdr.Protocol) +
5362 data_offset);
5363 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005364 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005365 }
5366 }
5367 cifs_buf_release(pSMB);
5368
5369 if (rc == -EAGAIN)
5370 goto QFSUnixRetry;
5371
5372
5373 return rc;
5374}
5375
Jeremy Allisonac670552005-06-22 17:26:35 -07005376int
Steve French96daf2b2011-05-27 04:34:02 +00005377CIFSSMBSetFSUnixInfo(const int xid, struct cifs_tcon *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07005378{
5379/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
5380 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
5381 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
5382 int rc = 0;
5383 int bytes_returned = 0;
5384 __u16 params, param_offset, offset, byte_count;
5385
Joe Perchesb6b38f72010-04-21 03:50:45 +00005386 cFYI(1, "In SETFSUnixInfo");
Jeremy Allisonac670552005-06-22 17:26:35 -07005387SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00005388 /* BB switch to small buf init to save memory */
Jeff Laytonf5695992010-09-29 15:27:08 -04005389 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5390 (void **) &pSMB, (void **) &pSMBr);
Jeremy Allisonac670552005-06-22 17:26:35 -07005391 if (rc)
5392 return rc;
5393
5394 params = 4; /* 2 bytes zero followed by info level. */
5395 pSMB->MaxSetupCount = 0;
5396 pSMB->Reserved = 0;
5397 pSMB->Flags = 0;
5398 pSMB->Timeout = 0;
5399 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00005400 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
5401 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07005402 offset = param_offset + params;
5403
5404 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00005405 /* BB find exact max SMB PDU from sess structure BB */
5406 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07005407 pSMB->SetupCount = 1;
5408 pSMB->Reserved3 = 0;
5409 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
5410 byte_count = 1 /* pad */ + params + 12;
5411
5412 pSMB->DataCount = cpu_to_le16(12);
5413 pSMB->ParameterCount = cpu_to_le16(params);
5414 pSMB->TotalDataCount = pSMB->DataCount;
5415 pSMB->TotalParameterCount = pSMB->ParameterCount;
5416 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5417 pSMB->DataOffset = cpu_to_le16(offset);
5418
5419 /* Params. */
5420 pSMB->FileNum = 0;
5421 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
5422
5423 /* Data. */
5424 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
5425 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
5426 pSMB->ClientUnixCap = cpu_to_le64(cap);
5427
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005428 inc_rfc1001_len(pSMB, byte_count);
Jeremy Allisonac670552005-06-22 17:26:35 -07005429 pSMB->ByteCount = cpu_to_le16(byte_count);
5430
5431 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5432 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5433 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005434 cERROR(1, "Send error in SETFSUnixInfo = %d", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07005435 } else { /* decode response */
5436 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00005437 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07005438 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07005439 }
5440 cifs_buf_release(pSMB);
5441
5442 if (rc == -EAGAIN)
5443 goto SETFSUnixRetry;
5444
5445 return rc;
5446}
5447
5448
Linus Torvalds1da177e2005-04-16 15:20:36 -07005449
5450int
Steve French96daf2b2011-05-27 04:34:02 +00005451CIFSSMBQFSPosixInfo(const int xid, struct cifs_tcon *tcon,
Steve French737b7582005-04-28 22:41:06 -07005452 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005453{
5454/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
5455 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5456 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5457 FILE_SYSTEM_POSIX_INFO *response_data;
5458 int rc = 0;
5459 int bytes_returned = 0;
5460 __u16 params, byte_count;
5461
Joe Perchesb6b38f72010-04-21 03:50:45 +00005462 cFYI(1, "In QFSPosixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005463QFSPosixRetry:
5464 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5465 (void **) &pSMBr);
5466 if (rc)
5467 return rc;
5468
5469 params = 2; /* level */
5470 pSMB->TotalDataCount = 0;
5471 pSMB->DataCount = 0;
5472 pSMB->DataOffset = 0;
5473 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005474 /* BB find exact max SMB PDU from sess structure BB */
5475 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005476 pSMB->MaxSetupCount = 0;
5477 pSMB->Reserved = 0;
5478 pSMB->Flags = 0;
5479 pSMB->Timeout = 0;
5480 pSMB->Reserved2 = 0;
5481 byte_count = params + 1 /* pad */ ;
5482 pSMB->ParameterCount = cpu_to_le16(params);
5483 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005484 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5485 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005486 pSMB->SetupCount = 1;
5487 pSMB->Reserved3 = 0;
5488 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5489 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005490 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005491 pSMB->ByteCount = cpu_to_le16(byte_count);
5492
5493 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5494 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5495 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005496 cFYI(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005497 } else { /* decode response */
5498 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5499
Jeff Layton820a8032011-05-04 08:05:26 -04005500 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005501 rc = -EIO; /* bad smb */
5502 } else {
5503 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5504 response_data =
5505 (FILE_SYSTEM_POSIX_INFO
5506 *) (((char *) &pSMBr->hdr.Protocol) +
5507 data_offset);
5508 FSData->f_bsize =
5509 le32_to_cpu(response_data->BlockSize);
5510 FSData->f_blocks =
5511 le64_to_cpu(response_data->TotalBlocks);
5512 FSData->f_bfree =
5513 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00005514 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005515 FSData->f_bavail = FSData->f_bfree;
5516 } else {
5517 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00005518 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005519 }
Steve French790fe572007-07-07 19:25:05 +00005520 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005521 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00005522 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00005523 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005524 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00005525 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005526 }
5527 }
5528 cifs_buf_release(pSMB);
5529
5530 if (rc == -EAGAIN)
5531 goto QFSPosixRetry;
5532
5533 return rc;
5534}
5535
5536
Steve French50c2f752007-07-13 00:33:32 +00005537/* We can not use write of zero bytes trick to
5538 set file size due to need for large file support. Also note that
5539 this SetPathInfo is preferred to SetFileInfo based method in next
Linus Torvalds1da177e2005-04-16 15:20:36 -07005540 routine which is only needed to work around a sharing violation bug
5541 in Samba which this routine can run into */
5542
5543int
Steve French96daf2b2011-05-27 04:34:02 +00005544CIFSSMBSetEOF(const int xid, struct cifs_tcon *tcon, const char *fileName,
Steve French4b18f2a2008-04-29 00:06:05 +00005545 __u64 size, bool SetAllocation,
Steve French737b7582005-04-28 22:41:06 -07005546 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005547{
5548 struct smb_com_transaction2_spi_req *pSMB = NULL;
5549 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5550 struct file_end_of_file_info *parm_data;
5551 int name_len;
5552 int rc = 0;
5553 int bytes_returned = 0;
5554 __u16 params, byte_count, data_count, param_offset, offset;
5555
Joe Perchesb6b38f72010-04-21 03:50:45 +00005556 cFYI(1, "In SetEOF");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005557SetEOFRetry:
5558 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5559 (void **) &pSMBr);
5560 if (rc)
5561 return rc;
5562
5563 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5564 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005565 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5566 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005567 name_len++; /* trailing null */
5568 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005569 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005570 name_len = strnlen(fileName, PATH_MAX);
5571 name_len++; /* trailing null */
5572 strncpy(pSMB->FileName, fileName, name_len);
5573 }
5574 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005575 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005576 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07005577 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005578 pSMB->MaxSetupCount = 0;
5579 pSMB->Reserved = 0;
5580 pSMB->Flags = 0;
5581 pSMB->Timeout = 0;
5582 pSMB->Reserved2 = 0;
5583 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005584 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005585 offset = param_offset + params;
Steve French790fe572007-07-07 19:25:05 +00005586 if (SetAllocation) {
Steve French50c2f752007-07-13 00:33:32 +00005587 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5588 pSMB->InformationLevel =
5589 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5590 else
5591 pSMB->InformationLevel =
5592 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5593 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005594 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5595 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005596 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005597 else
5598 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005599 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005600 }
5601
5602 parm_data =
5603 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
5604 offset);
5605 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5606 pSMB->DataOffset = cpu_to_le16(offset);
5607 pSMB->SetupCount = 1;
5608 pSMB->Reserved3 = 0;
5609 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5610 byte_count = 3 /* pad */ + params + data_count;
5611 pSMB->DataCount = cpu_to_le16(data_count);
5612 pSMB->TotalDataCount = pSMB->DataCount;
5613 pSMB->ParameterCount = cpu_to_le16(params);
5614 pSMB->TotalParameterCount = pSMB->ParameterCount;
5615 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005616 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005617 parm_data->FileSize = cpu_to_le64(size);
5618 pSMB->ByteCount = cpu_to_le16(byte_count);
5619 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5620 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005621 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005622 cFYI(1, "SetPathInfo (file size) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005623
5624 cifs_buf_release(pSMB);
5625
5626 if (rc == -EAGAIN)
5627 goto SetEOFRetry;
5628
5629 return rc;
5630}
5631
5632int
Steve French96daf2b2011-05-27 04:34:02 +00005633CIFSSMBSetFileSize(const int xid, struct cifs_tcon *tcon, __u64 size,
Steve French4b18f2a2008-04-29 00:06:05 +00005634 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005635{
5636 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005637 struct file_end_of_file_info *parm_data;
5638 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005639 __u16 params, param_offset, offset, byte_count, count;
5640
Joe Perchesb6b38f72010-04-21 03:50:45 +00005641 cFYI(1, "SetFileSize (via SetFileInfo) %lld",
5642 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07005643 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5644
Linus Torvalds1da177e2005-04-16 15:20:36 -07005645 if (rc)
5646 return rc;
5647
5648 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5649 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005650
Linus Torvalds1da177e2005-04-16 15:20:36 -07005651 params = 6;
5652 pSMB->MaxSetupCount = 0;
5653 pSMB->Reserved = 0;
5654 pSMB->Flags = 0;
5655 pSMB->Timeout = 0;
5656 pSMB->Reserved2 = 0;
5657 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5658 offset = param_offset + params;
5659
Linus Torvalds1da177e2005-04-16 15:20:36 -07005660 count = sizeof(struct file_end_of_file_info);
5661 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005662 /* BB find exact max SMB PDU from sess structure BB */
5663 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005664 pSMB->SetupCount = 1;
5665 pSMB->Reserved3 = 0;
5666 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5667 byte_count = 3 /* pad */ + params + count;
5668 pSMB->DataCount = cpu_to_le16(count);
5669 pSMB->ParameterCount = cpu_to_le16(params);
5670 pSMB->TotalDataCount = pSMB->DataCount;
5671 pSMB->TotalParameterCount = pSMB->ParameterCount;
5672 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5673 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00005674 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
5675 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005676 pSMB->DataOffset = cpu_to_le16(offset);
5677 parm_data->FileSize = cpu_to_le64(size);
5678 pSMB->Fid = fid;
Steve French790fe572007-07-07 19:25:05 +00005679 if (SetAllocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005680 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5681 pSMB->InformationLevel =
5682 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5683 else
5684 pSMB->InformationLevel =
5685 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00005686 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005687 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5688 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005689 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005690 else
5691 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005692 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005693 }
5694 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005695 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005696 pSMB->ByteCount = cpu_to_le16(byte_count);
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005697 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005698 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005699 cFYI(1, "Send error in SetFileInfo (SetFileSize) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005700 }
5701
Steve French50c2f752007-07-13 00:33:32 +00005702 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005703 since file handle passed in no longer valid */
5704
5705 return rc;
5706}
5707
Steve French50c2f752007-07-13 00:33:32 +00005708/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07005709 an open handle, rather than by pathname - this is awkward due to
5710 potential access conflicts on the open, but it is unavoidable for these
5711 old servers since the only other choice is to go from 100 nanosecond DCE
5712 time and resort to the original setpathinfo level which takes the ancient
5713 DOS time format with 2 second granularity */
5714int
Steve French96daf2b2011-05-27 04:34:02 +00005715CIFSSMBSetFileInfo(const int xid, struct cifs_tcon *tcon,
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005716 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005717{
5718 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005719 char *data_offset;
5720 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005721 __u16 params, param_offset, offset, byte_count, count;
5722
Joe Perchesb6b38f72010-04-21 03:50:45 +00005723 cFYI(1, "Set Times (via SetFileInfo)");
Steve Frenchcd634992005-04-28 22:41:10 -07005724 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5725
Linus Torvalds1da177e2005-04-16 15:20:36 -07005726 if (rc)
5727 return rc;
5728
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005729 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5730 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005731
Linus Torvalds1da177e2005-04-16 15:20:36 -07005732 params = 6;
5733 pSMB->MaxSetupCount = 0;
5734 pSMB->Reserved = 0;
5735 pSMB->Flags = 0;
5736 pSMB->Timeout = 0;
5737 pSMB->Reserved2 = 0;
5738 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5739 offset = param_offset + params;
5740
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005741 data_offset = (char *)pSMB +
5742 offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005743
Steve French26f57362007-08-30 22:09:15 +00005744 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005745 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005746 /* BB find max SMB PDU from sess */
5747 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005748 pSMB->SetupCount = 1;
5749 pSMB->Reserved3 = 0;
5750 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5751 byte_count = 3 /* pad */ + params + count;
5752 pSMB->DataCount = cpu_to_le16(count);
5753 pSMB->ParameterCount = cpu_to_le16(params);
5754 pSMB->TotalDataCount = pSMB->DataCount;
5755 pSMB->TotalParameterCount = pSMB->ParameterCount;
5756 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5757 pSMB->DataOffset = cpu_to_le16(offset);
5758 pSMB->Fid = fid;
5759 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5760 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5761 else
5762 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5763 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005764 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005765 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005766 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005767 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005768 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005769 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005770
Steve French50c2f752007-07-13 00:33:32 +00005771 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005772 since file handle passed in no longer valid */
5773
5774 return rc;
5775}
5776
Jeff Layton6d22f092008-09-23 11:48:35 -04005777int
Steve French96daf2b2011-05-27 04:34:02 +00005778CIFSSMBSetFileDisposition(const int xid, struct cifs_tcon *tcon,
Jeff Layton6d22f092008-09-23 11:48:35 -04005779 bool delete_file, __u16 fid, __u32 pid_of_opener)
5780{
5781 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5782 char *data_offset;
5783 int rc = 0;
5784 __u16 params, param_offset, offset, byte_count, count;
5785
Joe Perchesb6b38f72010-04-21 03:50:45 +00005786 cFYI(1, "Set File Disposition (via SetFileInfo)");
Jeff Layton6d22f092008-09-23 11:48:35 -04005787 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5788
5789 if (rc)
5790 return rc;
5791
5792 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5793 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5794
5795 params = 6;
5796 pSMB->MaxSetupCount = 0;
5797 pSMB->Reserved = 0;
5798 pSMB->Flags = 0;
5799 pSMB->Timeout = 0;
5800 pSMB->Reserved2 = 0;
5801 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5802 offset = param_offset + params;
5803
5804 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5805
5806 count = 1;
5807 pSMB->MaxParameterCount = cpu_to_le16(2);
5808 /* BB find max SMB PDU from sess */
5809 pSMB->MaxDataCount = cpu_to_le16(1000);
5810 pSMB->SetupCount = 1;
5811 pSMB->Reserved3 = 0;
5812 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5813 byte_count = 3 /* pad */ + params + count;
5814 pSMB->DataCount = cpu_to_le16(count);
5815 pSMB->ParameterCount = cpu_to_le16(params);
5816 pSMB->TotalDataCount = pSMB->DataCount;
5817 pSMB->TotalParameterCount = pSMB->ParameterCount;
5818 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5819 pSMB->DataOffset = cpu_to_le16(offset);
5820 pSMB->Fid = fid;
5821 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5822 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005823 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton6d22f092008-09-23 11:48:35 -04005824 pSMB->ByteCount = cpu_to_le16(byte_count);
5825 *data_offset = delete_file ? 1 : 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005826 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Jeff Layton6d22f092008-09-23 11:48:35 -04005827 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005828 cFYI(1, "Send error in SetFileDisposition = %d", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005829
5830 return rc;
5831}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005832
5833int
Steve French96daf2b2011-05-27 04:34:02 +00005834CIFSSMBSetPathInfo(const int xid, struct cifs_tcon *tcon,
Jeff Layton6fc000e2008-08-02 07:26:12 -04005835 const char *fileName, const FILE_BASIC_INFO *data,
5836 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005837{
5838 TRANSACTION2_SPI_REQ *pSMB = NULL;
5839 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5840 int name_len;
5841 int rc = 0;
5842 int bytes_returned = 0;
5843 char *data_offset;
5844 __u16 params, param_offset, offset, byte_count, count;
5845
Joe Perchesb6b38f72010-04-21 03:50:45 +00005846 cFYI(1, "In SetTimes");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005847
5848SetTimesRetry:
5849 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5850 (void **) &pSMBr);
5851 if (rc)
5852 return rc;
5853
5854 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5855 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005856 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5857 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005858 name_len++; /* trailing null */
5859 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005860 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005861 name_len = strnlen(fileName, PATH_MAX);
5862 name_len++; /* trailing null */
5863 strncpy(pSMB->FileName, fileName, name_len);
5864 }
5865
5866 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005867 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005868 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005869 /* BB find max SMB PDU from sess structure BB */
5870 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005871 pSMB->MaxSetupCount = 0;
5872 pSMB->Reserved = 0;
5873 pSMB->Flags = 0;
5874 pSMB->Timeout = 0;
5875 pSMB->Reserved2 = 0;
5876 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005877 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005878 offset = param_offset + params;
5879 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5880 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5881 pSMB->DataOffset = cpu_to_le16(offset);
5882 pSMB->SetupCount = 1;
5883 pSMB->Reserved3 = 0;
5884 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5885 byte_count = 3 /* pad */ + params + count;
5886
5887 pSMB->DataCount = cpu_to_le16(count);
5888 pSMB->ParameterCount = cpu_to_le16(params);
5889 pSMB->TotalDataCount = pSMB->DataCount;
5890 pSMB->TotalParameterCount = pSMB->ParameterCount;
5891 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5892 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5893 else
5894 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5895 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005896 inc_rfc1001_len(pSMB, byte_count);
Steve French26f57362007-08-30 22:09:15 +00005897 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005898 pSMB->ByteCount = cpu_to_le16(byte_count);
5899 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5900 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005901 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005902 cFYI(1, "SetPathInfo (times) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005903
5904 cifs_buf_release(pSMB);
5905
5906 if (rc == -EAGAIN)
5907 goto SetTimesRetry;
5908
5909 return rc;
5910}
5911
5912/* Can not be used to set time stamps yet (due to old DOS time format) */
5913/* Can be used to set attributes */
5914#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5915 handling it anyway and NT4 was what we thought it would be needed for
5916 Do not delete it until we prove whether needed for Win9x though */
5917int
Steve French96daf2b2011-05-27 04:34:02 +00005918CIFSSMBSetAttrLegacy(int xid, struct cifs_tcon *tcon, char *fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005919 __u16 dos_attrs, const struct nls_table *nls_codepage)
5920{
5921 SETATTR_REQ *pSMB = NULL;
5922 SETATTR_RSP *pSMBr = NULL;
5923 int rc = 0;
5924 int bytes_returned;
5925 int name_len;
5926
Joe Perchesb6b38f72010-04-21 03:50:45 +00005927 cFYI(1, "In SetAttrLegacy");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005928
5929SetAttrLgcyRetry:
5930 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5931 (void **) &pSMBr);
5932 if (rc)
5933 return rc;
5934
5935 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5936 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005937 ConvertToUTF16((__le16 *) pSMB->fileName, fileName,
5938 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005939 name_len++; /* trailing null */
5940 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005941 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005942 name_len = strnlen(fileName, PATH_MAX);
5943 name_len++; /* trailing null */
5944 strncpy(pSMB->fileName, fileName, name_len);
5945 }
5946 pSMB->attr = cpu_to_le16(dos_attrs);
5947 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005948 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005949 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5950 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5951 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005952 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005953 cFYI(1, "Error in LegacySetAttr = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005954
5955 cifs_buf_release(pSMB);
5956
5957 if (rc == -EAGAIN)
5958 goto SetAttrLgcyRetry;
5959
5960 return rc;
5961}
5962#endif /* temporarily unneeded SetAttr legacy function */
5963
Jeff Layton654cf142009-07-09 20:02:49 -04005964static void
5965cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5966 const struct cifs_unix_set_info_args *args)
5967{
5968 u64 mode = args->mode;
5969
5970 /*
5971 * Samba server ignores set of file size to zero due to bugs in some
5972 * older clients, but we should be precise - we use SetFileSize to
5973 * set file size and do not want to truncate file size to zero
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005974 * accidentally as happened on one Samba server beta by putting
Jeff Layton654cf142009-07-09 20:02:49 -04005975 * zero instead of -1 here
5976 */
5977 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5978 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5979 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5980 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5981 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5982 data_offset->Uid = cpu_to_le64(args->uid);
5983 data_offset->Gid = cpu_to_le64(args->gid);
5984 /* better to leave device as zero when it is */
5985 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5986 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5987 data_offset->Permissions = cpu_to_le64(mode);
5988
5989 if (S_ISREG(mode))
5990 data_offset->Type = cpu_to_le32(UNIX_FILE);
5991 else if (S_ISDIR(mode))
5992 data_offset->Type = cpu_to_le32(UNIX_DIR);
5993 else if (S_ISLNK(mode))
5994 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5995 else if (S_ISCHR(mode))
5996 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5997 else if (S_ISBLK(mode))
5998 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5999 else if (S_ISFIFO(mode))
6000 data_offset->Type = cpu_to_le32(UNIX_FIFO);
6001 else if (S_ISSOCK(mode))
6002 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
6003}
6004
Linus Torvalds1da177e2005-04-16 15:20:36 -07006005int
Steve French96daf2b2011-05-27 04:34:02 +00006006CIFSSMBUnixSetFileInfo(const int xid, struct cifs_tcon *tcon,
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006007 const struct cifs_unix_set_info_args *args,
6008 u16 fid, u32 pid_of_opener)
6009{
6010 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04006011 char *data_offset;
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006012 int rc = 0;
6013 u16 params, param_offset, offset, byte_count, count;
6014
Joe Perchesb6b38f72010-04-21 03:50:45 +00006015 cFYI(1, "Set Unix Info (via SetFileInfo)");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006016 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
6017
6018 if (rc)
6019 return rc;
6020
6021 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
6022 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
6023
6024 params = 6;
6025 pSMB->MaxSetupCount = 0;
6026 pSMB->Reserved = 0;
6027 pSMB->Flags = 0;
6028 pSMB->Timeout = 0;
6029 pSMB->Reserved2 = 0;
6030 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
6031 offset = param_offset + params;
6032
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04006033 data_offset = (char *)pSMB +
6034 offsetof(struct smb_hdr, Protocol) + offset;
6035
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006036 count = sizeof(FILE_UNIX_BASIC_INFO);
6037
6038 pSMB->MaxParameterCount = cpu_to_le16(2);
6039 /* BB find max SMB PDU from sess */
6040 pSMB->MaxDataCount = cpu_to_le16(1000);
6041 pSMB->SetupCount = 1;
6042 pSMB->Reserved3 = 0;
6043 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
6044 byte_count = 3 /* pad */ + params + count;
6045 pSMB->DataCount = cpu_to_le16(count);
6046 pSMB->ParameterCount = cpu_to_le16(params);
6047 pSMB->TotalDataCount = pSMB->DataCount;
6048 pSMB->TotalParameterCount = pSMB->ParameterCount;
6049 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6050 pSMB->DataOffset = cpu_to_le16(offset);
6051 pSMB->Fid = fid;
6052 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6053 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006054 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006055 pSMB->ByteCount = cpu_to_le16(byte_count);
6056
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04006057 cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006058
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04006059 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006060 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00006061 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006062
6063 /* Note: On -EAGAIN error only caller can retry on handle based calls
6064 since file handle passed in no longer valid */
6065
6066 return rc;
6067}
6068
6069int
Steve French96daf2b2011-05-27 04:34:02 +00006070CIFSSMBUnixSetPathInfo(const int xid, struct cifs_tcon *tcon, char *fileName,
Jeff Layton01ea95e2009-07-09 20:02:49 -04006071 const struct cifs_unix_set_info_args *args,
6072 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006073{
6074 TRANSACTION2_SPI_REQ *pSMB = NULL;
6075 TRANSACTION2_SPI_RSP *pSMBr = NULL;
6076 int name_len;
6077 int rc = 0;
6078 int bytes_returned = 0;
6079 FILE_UNIX_BASIC_INFO *data_offset;
6080 __u16 params, param_offset, offset, count, byte_count;
6081
Joe Perchesb6b38f72010-04-21 03:50:45 +00006082 cFYI(1, "In SetUID/GID/Mode");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006083setPermsRetry:
6084 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6085 (void **) &pSMBr);
6086 if (rc)
6087 return rc;
6088
6089 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6090 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006091 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
6092 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006093 name_len++; /* trailing null */
6094 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07006095 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006096 name_len = strnlen(fileName, PATH_MAX);
6097 name_len++; /* trailing null */
6098 strncpy(pSMB->FileName, fileName, name_len);
6099 }
6100
6101 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00006102 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006103 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006104 /* BB find max SMB PDU from sess structure BB */
6105 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006106 pSMB->MaxSetupCount = 0;
6107 pSMB->Reserved = 0;
6108 pSMB->Flags = 0;
6109 pSMB->Timeout = 0;
6110 pSMB->Reserved2 = 0;
6111 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006112 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006113 offset = param_offset + params;
6114 data_offset =
6115 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
6116 offset);
6117 memset(data_offset, 0, count);
6118 pSMB->DataOffset = cpu_to_le16(offset);
6119 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6120 pSMB->SetupCount = 1;
6121 pSMB->Reserved3 = 0;
6122 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6123 byte_count = 3 /* pad */ + params + count;
6124 pSMB->ParameterCount = cpu_to_le16(params);
6125 pSMB->DataCount = cpu_to_le16(count);
6126 pSMB->TotalParameterCount = pSMB->ParameterCount;
6127 pSMB->TotalDataCount = pSMB->DataCount;
6128 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6129 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006130 inc_rfc1001_len(pSMB, byte_count);
Steve French50c2f752007-07-13 00:33:32 +00006131
Jeff Layton654cf142009-07-09 20:02:49 -04006132 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006133
6134 pSMB->ByteCount = cpu_to_le16(byte_count);
6135 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6136 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006137 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00006138 cFYI(1, "SetPathInfo (perms) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006139
Steve French0d817bc2008-05-22 02:02:03 +00006140 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006141 if (rc == -EAGAIN)
6142 goto setPermsRetry;
6143 return rc;
6144}
6145
Linus Torvalds1da177e2005-04-16 15:20:36 -07006146#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05006147/*
6148 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
6149 * function used by listxattr and getxattr type calls. When ea_name is set,
6150 * it looks for that attribute name and stuffs that value into the EAData
6151 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
6152 * buffer. In both cases, the return value is either the length of the
6153 * resulting data or a negative error code. If EAData is a NULL pointer then
6154 * the data isn't copied to it, but the length is returned.
6155 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006156ssize_t
Steve French96daf2b2011-05-27 04:34:02 +00006157CIFSSMBQAllEAs(const int xid, struct cifs_tcon *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05006158 const unsigned char *searchName, const unsigned char *ea_name,
6159 char *EAData, size_t buf_size,
6160 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006161{
6162 /* BB assumes one setup word */
6163 TRANSACTION2_QPI_REQ *pSMB = NULL;
6164 TRANSACTION2_QPI_RSP *pSMBr = NULL;
6165 int rc = 0;
6166 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05006167 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006168 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00006169 struct fea *temp_fea;
6170 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006171 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006172 __u16 params, byte_count, data_offset;
Jeff Layton5980fc92011-07-28 12:48:26 -04006173 unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006174
Joe Perchesb6b38f72010-04-21 03:50:45 +00006175 cFYI(1, "In Query All EAs path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006176QAllEAsRetry:
6177 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6178 (void **) &pSMBr);
6179 if (rc)
6180 return rc;
6181
6182 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05006183 list_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006184 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
6185 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05006186 list_len++; /* trailing null */
6187 list_len *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006188 } else { /* BB improve the check for buffer overruns BB */
Jeff Layton6e462b92010-02-10 16:18:26 -05006189 list_len = strnlen(searchName, PATH_MAX);
6190 list_len++; /* trailing null */
6191 strncpy(pSMB->FileName, searchName, list_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006192 }
6193
Jeff Layton6e462b92010-02-10 16:18:26 -05006194 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006195 pSMB->TotalDataCount = 0;
6196 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006197 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05006198 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006199 pSMB->MaxSetupCount = 0;
6200 pSMB->Reserved = 0;
6201 pSMB->Flags = 0;
6202 pSMB->Timeout = 0;
6203 pSMB->Reserved2 = 0;
6204 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00006205 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006206 pSMB->DataCount = 0;
6207 pSMB->DataOffset = 0;
6208 pSMB->SetupCount = 1;
6209 pSMB->Reserved3 = 0;
6210 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
6211 byte_count = params + 1 /* pad */ ;
6212 pSMB->TotalParameterCount = cpu_to_le16(params);
6213 pSMB->ParameterCount = pSMB->TotalParameterCount;
6214 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
6215 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006216 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006217 pSMB->ByteCount = cpu_to_le16(byte_count);
6218
6219 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6220 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6221 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006222 cFYI(1, "Send error in QueryAllEAs = %d", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05006223 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006224 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006225
6226
6227 /* BB also check enough total bytes returned */
6228 /* BB we need to improve the validity checking
6229 of these trans2 responses */
6230
6231 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Jeff Layton820a8032011-05-04 08:05:26 -04006232 if (rc || get_bcc(&pSMBr->hdr) < 4) {
Jeff Laytonf0d38682010-02-10 16:18:26 -05006233 rc = -EIO; /* bad smb */
6234 goto QAllEAsOut;
6235 }
6236
6237 /* check that length of list is not more than bcc */
6238 /* check that each entry does not go beyond length
6239 of list */
6240 /* check that each element of each entry does not
6241 go beyond end of list */
6242 /* validate_trans2_offsets() */
6243 /* BB check if start of smb + data_offset > &bcc+ bcc */
6244
6245 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
6246 ea_response_data = (struct fealist *)
6247 (((char *) &pSMBr->hdr.Protocol) + data_offset);
6248
Jeff Layton6e462b92010-02-10 16:18:26 -05006249 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesb6b38f72010-04-21 03:50:45 +00006250 cFYI(1, "ea length %d", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05006251 if (list_len <= 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006252 cFYI(1, "empty EA list returned from server");
Jeff Laytonf0d38682010-02-10 16:18:26 -05006253 goto QAllEAsOut;
6254 }
6255
Jeff Layton0cd126b2010-02-10 16:18:26 -05006256 /* make sure list_len doesn't go past end of SMB */
Jeff Layton690c5222011-01-20 13:36:51 -05006257 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
Jeff Layton0cd126b2010-02-10 16:18:26 -05006258 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006259 cFYI(1, "EA list appears to go beyond SMB");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006260 rc = -EIO;
6261 goto QAllEAsOut;
6262 }
6263
Jeff Laytonf0d38682010-02-10 16:18:26 -05006264 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05006265 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006266 temp_fea = ea_response_data->list;
6267 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05006268 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00006269 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006270 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006271
Jeff Layton6e462b92010-02-10 16:18:26 -05006272 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006273 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006274 /* make sure we can read name_len and value_len */
6275 if (list_len < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006276 cFYI(1, "EA entry goes beyond length of list");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006277 rc = -EIO;
6278 goto QAllEAsOut;
6279 }
6280
6281 name_len = temp_fea->name_len;
6282 value_len = le16_to_cpu(temp_fea->value_len);
6283 list_len -= name_len + 1 + value_len;
6284 if (list_len < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006285 cFYI(1, "EA entry goes beyond length of list");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006286 rc = -EIO;
6287 goto QAllEAsOut;
6288 }
6289
Jeff Layton31c05192010-02-10 16:18:26 -05006290 if (ea_name) {
Jeff Layton91d065c2011-07-26 18:23:47 -04006291 if (ea_name_len == name_len &&
Jeff Laytonac423442011-10-11 06:41:32 -04006292 memcmp(ea_name, temp_ptr, name_len) == 0) {
Jeff Layton31c05192010-02-10 16:18:26 -05006293 temp_ptr += name_len + 1;
6294 rc = value_len;
6295 if (buf_size == 0)
6296 goto QAllEAsOut;
6297 if ((size_t)value_len > buf_size) {
6298 rc = -ERANGE;
6299 goto QAllEAsOut;
6300 }
6301 memcpy(EAData, temp_ptr, value_len);
6302 goto QAllEAsOut;
6303 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006304 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05006305 /* account for prefix user. and trailing null */
6306 rc += (5 + 1 + name_len);
6307 if (rc < (int) buf_size) {
6308 memcpy(EAData, "user.", 5);
6309 EAData += 5;
6310 memcpy(EAData, temp_ptr, name_len);
6311 EAData += name_len;
6312 /* null terminate name */
6313 *EAData = 0;
6314 ++EAData;
6315 } else if (buf_size == 0) {
6316 /* skip copy - calc size only */
6317 } else {
6318 /* stop before overrun buffer */
6319 rc = -ERANGE;
6320 break;
6321 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006322 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05006323 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006324 temp_fea = (struct fea *)temp_ptr;
6325 }
6326
Jeff Layton31c05192010-02-10 16:18:26 -05006327 /* didn't find the named attribute */
6328 if (ea_name)
6329 rc = -ENODATA;
6330
Jeff Laytonf0d38682010-02-10 16:18:26 -05006331QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00006332 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006333 if (rc == -EAGAIN)
6334 goto QAllEAsRetry;
6335
6336 return (ssize_t)rc;
6337}
6338
Linus Torvalds1da177e2005-04-16 15:20:36 -07006339int
Steve French96daf2b2011-05-27 04:34:02 +00006340CIFSSMBSetEA(const int xid, struct cifs_tcon *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00006341 const char *ea_name, const void *ea_value,
6342 const __u16 ea_value_len, const struct nls_table *nls_codepage,
6343 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006344{
6345 struct smb_com_transaction2_spi_req *pSMB = NULL;
6346 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
6347 struct fealist *parm_data;
6348 int name_len;
6349 int rc = 0;
6350 int bytes_returned = 0;
6351 __u16 params, param_offset, byte_count, offset, count;
6352
Joe Perchesb6b38f72010-04-21 03:50:45 +00006353 cFYI(1, "In SetEA");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006354SetEARetry:
6355 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6356 (void **) &pSMBr);
6357 if (rc)
6358 return rc;
6359
6360 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6361 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006362 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
6363 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006364 name_len++; /* trailing null */
6365 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00006366 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006367 name_len = strnlen(fileName, PATH_MAX);
6368 name_len++; /* trailing null */
6369 strncpy(pSMB->FileName, fileName, name_len);
6370 }
6371
6372 params = 6 + name_len;
6373
6374 /* done calculating parms using name_len of file name,
6375 now use name_len to calculate length of ea name
6376 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00006377 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006378 name_len = 0;
6379 else
Steve French50c2f752007-07-13 00:33:32 +00006380 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006381
Steve Frenchdae5dbd2007-12-30 23:49:57 +00006382 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006383 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006384 /* BB find max SMB PDU from sess */
6385 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006386 pSMB->MaxSetupCount = 0;
6387 pSMB->Reserved = 0;
6388 pSMB->Flags = 0;
6389 pSMB->Timeout = 0;
6390 pSMB->Reserved2 = 0;
6391 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006392 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006393 offset = param_offset + params;
6394 pSMB->InformationLevel =
6395 cpu_to_le16(SMB_SET_FILE_EA);
6396
6397 parm_data =
6398 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
6399 offset);
6400 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6401 pSMB->DataOffset = cpu_to_le16(offset);
6402 pSMB->SetupCount = 1;
6403 pSMB->Reserved3 = 0;
6404 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6405 byte_count = 3 /* pad */ + params + count;
6406 pSMB->DataCount = cpu_to_le16(count);
6407 parm_data->list_len = cpu_to_le32(count);
6408 parm_data->list[0].EA_flags = 0;
6409 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08006410 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006411 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00006412 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00006413 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006414 parm_data->list[0].name[name_len] = 0;
6415 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
6416 /* caller ensures that ea_value_len is less than 64K but
6417 we need to ensure that it fits within the smb */
6418
Steve French50c2f752007-07-13 00:33:32 +00006419 /*BB add length check to see if it would fit in
6420 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00006421 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
6422 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00006423 memcpy(parm_data->list[0].name+name_len+1,
6424 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006425
6426 pSMB->TotalDataCount = pSMB->DataCount;
6427 pSMB->ParameterCount = cpu_to_le16(params);
6428 pSMB->TotalParameterCount = pSMB->ParameterCount;
6429 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006430 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006431 pSMB->ByteCount = cpu_to_le16(byte_count);
6432 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6433 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006434 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00006435 cFYI(1, "SetPathInfo (EA) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006436
6437 cifs_buf_release(pSMB);
6438
6439 if (rc == -EAGAIN)
6440 goto SetEARetry;
6441
6442 return rc;
6443}
Linus Torvalds1da177e2005-04-16 15:20:36 -07006444#endif
Steve French0eff0e22011-02-24 05:39:23 +00006445
6446#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */
6447/*
6448 * Years ago the kernel added a "dnotify" function for Samba server,
6449 * to allow network clients (such as Windows) to display updated
6450 * lists of files in directory listings automatically when
6451 * files are added by one user when another user has the
6452 * same directory open on their desktop. The Linux cifs kernel
6453 * client hooked into the kernel side of this interface for
6454 * the same reason, but ironically when the VFS moved from
6455 * "dnotify" to "inotify" it became harder to plug in Linux
6456 * network file system clients (the most obvious use case
6457 * for notify interfaces is when multiple users can update
6458 * the contents of the same directory - exactly what network
6459 * file systems can do) although the server (Samba) could
6460 * still use it. For the short term we leave the worker
6461 * function ifdeffed out (below) until inotify is fixed
6462 * in the VFS to make it easier to plug in network file
6463 * system clients. If inotify turns out to be permanently
6464 * incompatible for network fs clients, we could instead simply
6465 * expose this config flag by adding a future cifs (and smb2) notify ioctl.
6466 */
Steve French96daf2b2011-05-27 04:34:02 +00006467int CIFSSMBNotify(const int xid, struct cifs_tcon *tcon,
Steve French0eff0e22011-02-24 05:39:23 +00006468 const int notify_subdirs, const __u16 netfid,
6469 __u32 filter, struct file *pfile, int multishot,
6470 const struct nls_table *nls_codepage)
6471{
6472 int rc = 0;
6473 struct smb_com_transaction_change_notify_req *pSMB = NULL;
6474 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
6475 struct dir_notify_req *dnotify_req;
6476 int bytes_returned;
6477
6478 cFYI(1, "In CIFSSMBNotify for file handle %d", (int)netfid);
6479 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
6480 (void **) &pSMBr);
6481 if (rc)
6482 return rc;
6483
6484 pSMB->TotalParameterCount = 0 ;
6485 pSMB->TotalDataCount = 0;
6486 pSMB->MaxParameterCount = cpu_to_le32(2);
Jeff Laytonc974bef2011-10-11 06:41:32 -04006487 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Steve French0eff0e22011-02-24 05:39:23 +00006488 pSMB->MaxSetupCount = 4;
6489 pSMB->Reserved = 0;
6490 pSMB->ParameterOffset = 0;
6491 pSMB->DataCount = 0;
6492 pSMB->DataOffset = 0;
6493 pSMB->SetupCount = 4; /* single byte does not need le conversion */
6494 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
6495 pSMB->ParameterCount = pSMB->TotalParameterCount;
6496 if (notify_subdirs)
6497 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
6498 pSMB->Reserved2 = 0;
6499 pSMB->CompletionFilter = cpu_to_le32(filter);
6500 pSMB->Fid = netfid; /* file handle always le */
6501 pSMB->ByteCount = 0;
6502
6503 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6504 (struct smb_hdr *)pSMBr, &bytes_returned,
6505 CIFS_ASYNC_OP);
6506 if (rc) {
6507 cFYI(1, "Error in Notify = %d", rc);
6508 } else {
6509 /* Add file to outstanding requests */
6510 /* BB change to kmem cache alloc */
6511 dnotify_req = kmalloc(
6512 sizeof(struct dir_notify_req),
6513 GFP_KERNEL);
6514 if (dnotify_req) {
6515 dnotify_req->Pid = pSMB->hdr.Pid;
6516 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
6517 dnotify_req->Mid = pSMB->hdr.Mid;
6518 dnotify_req->Tid = pSMB->hdr.Tid;
6519 dnotify_req->Uid = pSMB->hdr.Uid;
6520 dnotify_req->netfid = netfid;
6521 dnotify_req->pfile = pfile;
6522 dnotify_req->filter = filter;
6523 dnotify_req->multishot = multishot;
6524 spin_lock(&GlobalMid_Lock);
6525 list_add_tail(&dnotify_req->lhead,
6526 &GlobalDnotifyReqList);
6527 spin_unlock(&GlobalMid_Lock);
6528 } else
6529 rc = -ENOMEM;
6530 }
6531 cifs_buf_release(pSMB);
6532 return rc;
6533}
6534#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */