blob: f0cf934ba877d8549d8631787a4aea8da871b371 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/cifssmb.c
3 *
Steve Frenchf19159d2010-04-21 04:12:10 +00004 * Copyright (C) International Business Machines Corp., 2002,2010
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * Author(s): Steve French (sfrench@us.ibm.com)
6 *
7 * Contains the routines for constructing the SMB PDUs themselves
8 *
9 * This library is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as published
11 * by the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
17 * the GNU Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24 /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c */
25 /* These are mostly routines that operate on a pathname, or on a tree id */
26 /* (mounted volume), but there are eight handle based routines which must be */
Steve French2dd29d32007-04-23 22:07:35 +000027 /* treated slightly differently for reconnection purposes since we never */
28 /* want to reuse a stale file handle and only the caller knows the file info */
Linus Torvalds1da177e2005-04-16 15:20:36 -070029
30#include <linux/fs.h>
31#include <linux/kernel.h>
32#include <linux/vfs.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090033#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include <linux/posix_acl_xattr.h>
Jeff Laytonc28c89f2011-05-19 16:22:56 -040035#include <linux/pagemap.h>
Jeff Laytone28bc5b2011-10-19 15:30:07 -040036#include <linux/swap.h>
37#include <linux/task_io_accounting_ops.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070038#include <asm/uaccess.h>
39#include "cifspdu.h"
40#include "cifsglob.h"
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +000041#include "cifsacl.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070042#include "cifsproto.h"
43#include "cifs_unicode.h"
44#include "cifs_debug.h"
Jeff Laytone28bc5b2011-10-19 15:30:07 -040045#include "fscache.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070046
47#ifdef CONFIG_CIFS_POSIX
48static struct {
49 int index;
50 char *name;
51} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000052#ifdef CONFIG_CIFS_WEAK_PW_HASH
53 {LANMAN_PROT, "\2LM1.2X002"},
Steve French9ac00b72006-09-30 04:13:17 +000054 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000055#endif /* weak password hashing for legacy clients */
Steve French50c2f752007-07-13 00:33:32 +000056 {CIFS_PROT, "\2NT LM 0.12"},
Steve French39798772006-05-31 22:40:51 +000057 {POSIX_PROT, "\2POSIX 2"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070058 {BAD_PROT, "\2"}
59};
60#else
61static struct {
62 int index;
63 char *name;
64} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000065#ifdef CONFIG_CIFS_WEAK_PW_HASH
66 {LANMAN_PROT, "\2LM1.2X002"},
Steve French18f75ca2006-10-01 03:13:01 +000067 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000068#endif /* weak password hashing for legacy clients */
Steve French790fe572007-07-07 19:25:05 +000069 {CIFS_PROT, "\2NT LM 0.12"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070070 {BAD_PROT, "\2"}
71};
72#endif
73
Steve French39798772006-05-31 22:40:51 +000074/* define the number of elements in the cifs dialect array */
75#ifdef CONFIG_CIFS_POSIX
76#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000077#define CIFS_NUM_PROT 4
Steve French39798772006-05-31 22:40:51 +000078#else
79#define CIFS_NUM_PROT 2
80#endif /* CIFS_WEAK_PW_HASH */
81#else /* not posix */
82#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000083#define CIFS_NUM_PROT 3
Steve French39798772006-05-31 22:40:51 +000084#else
85#define CIFS_NUM_PROT 1
86#endif /* CONFIG_CIFS_WEAK_PW_HASH */
87#endif /* CIFS_POSIX */
88
Jeff Layton3cf003c2012-07-11 09:09:36 -040089#ifdef CONFIG_HIGHMEM
90/*
91 * On arches that have high memory, kmap address space is limited. By
92 * serializing the kmap operations on those arches, we ensure that we don't
93 * end up with a bunch of threads in writeback with partially mapped page
94 * arrays, stuck waiting for kmap to come back. That situation prevents
95 * progress and can deadlock.
96 */
97static DEFINE_MUTEX(cifs_kmap_mutex);
98
99static inline void
100cifs_kmap_lock(void)
101{
102 mutex_lock(&cifs_kmap_mutex);
103}
104
105static inline void
106cifs_kmap_unlock(void)
107{
108 mutex_unlock(&cifs_kmap_mutex);
109}
110#else /* !CONFIG_HIGHMEM */
111#define cifs_kmap_lock() do { ; } while(0)
112#define cifs_kmap_unlock() do { ; } while(0)
113#endif /* CONFIG_HIGHMEM */
Jeff Laytone28bc5b2011-10-19 15:30:07 -0400114
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400115/*
116 * Mark as invalid, all open files on tree connections since they
117 * were closed when session to server was lost.
118 */
119void
120cifs_mark_open_files_invalid(struct cifs_tcon *tcon)
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
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400126 /* 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);
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400128 list_for_each_safe(tmp, tmp1, &tcon->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);
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400134 /*
135 * BB Add call to invalidate_inodes(sb) for all superblocks mounted
136 * to this tcon.
137 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138}
139
Jeff Layton9162ab22009-09-03 12:07:17 -0400140/* reconnect the socket, tcon, and smb session if needed */
141static int
Steve French96daf2b2011-05-27 04:34:02 +0000142cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
Jeff Layton9162ab22009-09-03 12:07:17 -0400143{
Jeff Laytonc4a55342011-07-28 12:40:36 -0400144 int rc;
Steve French96daf2b2011-05-27 04:34:02 +0000145 struct cifs_ses *ses;
Jeff Layton9162ab22009-09-03 12:07:17 -0400146 struct TCP_Server_Info *server;
147 struct nls_table *nls_codepage;
148
149 /*
150 * SMBs NegProt, SessSetup, uLogoff do not have tcon yet so check for
151 * tcp and smb session status done differently for those three - in the
152 * calling routine
153 */
154 if (!tcon)
155 return 0;
156
157 ses = tcon->ses;
158 server = ses->server;
159
160 /*
161 * only tree disconnect, open, and write, (and ulogoff which does not
162 * have tcon) are allowed as we start force umount
163 */
164 if (tcon->tidStatus == CifsExiting) {
165 if (smb_command != SMB_COM_WRITE_ANDX &&
166 smb_command != SMB_COM_OPEN_ANDX &&
167 smb_command != SMB_COM_TREE_DISCONNECT) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000168 cFYI(1, "can not send cmd %d while umounting",
169 smb_command);
Jeff Layton9162ab22009-09-03 12:07:17 -0400170 return -ENODEV;
171 }
172 }
173
Jeff Layton9162ab22009-09-03 12:07:17 -0400174 /*
175 * Give demultiplex thread up to 10 seconds to reconnect, should be
176 * greater than cifs socket timeout which is 7 seconds
177 */
178 while (server->tcpStatus == CifsNeedReconnect) {
179 wait_event_interruptible_timeout(server->response_q,
Steve Frenchfd88ce92011-04-12 01:01:14 +0000180 (server->tcpStatus != CifsNeedReconnect), 10 * HZ);
Jeff Layton9162ab22009-09-03 12:07:17 -0400181
Steve Frenchfd88ce92011-04-12 01:01:14 +0000182 /* are we still trying to reconnect? */
Jeff Layton9162ab22009-09-03 12:07:17 -0400183 if (server->tcpStatus != CifsNeedReconnect)
184 break;
185
186 /*
187 * on "soft" mounts we wait once. Hard mounts keep
188 * retrying until process is killed or server comes
189 * back on-line
190 */
Jeff Laytond4025392011-02-07 08:54:35 -0500191 if (!tcon->retry) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000192 cFYI(1, "gave up waiting on reconnect in smb_init");
Jeff Layton9162ab22009-09-03 12:07:17 -0400193 return -EHOSTDOWN;
194 }
195 }
196
197 if (!ses->need_reconnect && !tcon->need_reconnect)
198 return 0;
199
200 nls_codepage = load_nls_default();
201
202 /*
203 * need to prevent multiple threads trying to simultaneously
204 * reconnect the same SMB session
205 */
Steve Frenchd7b619c2010-02-25 05:36:46 +0000206 mutex_lock(&ses->session_mutex);
Jeff Layton198b5682010-04-24 07:57:48 -0400207 rc = cifs_negotiate_protocol(0, ses);
208 if (rc == 0 && ses->need_reconnect)
Jeff Layton9162ab22009-09-03 12:07:17 -0400209 rc = cifs_setup_session(0, ses, nls_codepage);
210
211 /* do we need to reconnect tcon? */
212 if (rc || !tcon->need_reconnect) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000213 mutex_unlock(&ses->session_mutex);
Jeff Layton9162ab22009-09-03 12:07:17 -0400214 goto out;
215 }
216
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400217 cifs_mark_open_files_invalid(tcon);
Jeff Layton9162ab22009-09-03 12:07:17 -0400218 rc = CIFSTCon(0, ses, tcon->treeName, tcon, nls_codepage);
Steve Frenchd7b619c2010-02-25 05:36:46 +0000219 mutex_unlock(&ses->session_mutex);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000220 cFYI(1, "reconnect tcon rc = %d", rc);
Jeff Layton9162ab22009-09-03 12:07:17 -0400221
222 if (rc)
223 goto out;
224
225 /*
226 * FIXME: check if wsize needs updated due to negotiated smb buffer
227 * size shrinking
228 */
229 atomic_inc(&tconInfoReconnectCount);
230
231 /* tell server Unix caps we support */
232 if (ses->capabilities & CAP_UNIX)
233 reset_cifs_unix_caps(0, tcon, NULL, NULL);
234
235 /*
236 * Removed call to reopen open files here. It is safer (and faster) to
237 * reopen files one at a time as needed in read and write.
238 *
239 * FIXME: what about file locks? don't we need to reclaim them ASAP?
240 */
241
242out:
243 /*
244 * Check if handle based operation so we know whether we can continue
245 * or not without returning to caller to reset file handle
246 */
247 switch (smb_command) {
248 case SMB_COM_READ_ANDX:
249 case SMB_COM_WRITE_ANDX:
250 case SMB_COM_CLOSE:
251 case SMB_COM_FIND_CLOSE2:
252 case SMB_COM_LOCKING_ANDX:
253 rc = -EAGAIN;
254 }
255
256 unload_nls(nls_codepage);
257 return rc;
258}
259
Steve Frenchad7a2922008-02-07 23:25:02 +0000260/* Allocate and return pointer to an SMB request buffer, and set basic
261 SMB information in the SMB header. If the return code is zero, this
262 function must have filled in request_buf pointer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263static int
Steve French96daf2b2011-05-27 04:34:02 +0000264small_smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000265 void **request_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266{
Jeff Laytonf5695992010-09-29 15:27:08 -0400267 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268
Jeff Layton9162ab22009-09-03 12:07:17 -0400269 rc = cifs_reconnect_tcon(tcon, smb_command);
Steve French790fe572007-07-07 19:25:05 +0000270 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 return rc;
272
273 *request_buf = cifs_small_buf_get();
274 if (*request_buf == NULL) {
275 /* BB should we add a retry in here if not a writepage? */
276 return -ENOMEM;
277 }
278
Steve French63135e02007-07-17 17:34:02 +0000279 header_assemble((struct smb_hdr *) *request_buf, smb_command,
Steve Frenchc18c8422007-07-18 23:21:09 +0000280 tcon, wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281
Steve French790fe572007-07-07 19:25:05 +0000282 if (tcon != NULL)
283 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700284
Jeff Laytonf5695992010-09-29 15:27:08 -0400285 return 0;
Steve French5815449d2006-02-14 01:36:20 +0000286}
287
Steve French12b3b8f2006-02-09 21:12:47 +0000288int
Steve French50c2f752007-07-13 00:33:32 +0000289small_smb_init_no_tc(const int smb_command, const int wct,
Steve French96daf2b2011-05-27 04:34:02 +0000290 struct cifs_ses *ses, void **request_buf)
Steve French12b3b8f2006-02-09 21:12:47 +0000291{
292 int rc;
Steve French50c2f752007-07-13 00:33:32 +0000293 struct smb_hdr *buffer;
Steve French12b3b8f2006-02-09 21:12:47 +0000294
Steve French5815449d2006-02-14 01:36:20 +0000295 rc = small_smb_init(smb_command, wct, NULL, request_buf);
Steve French790fe572007-07-07 19:25:05 +0000296 if (rc)
Steve French12b3b8f2006-02-09 21:12:47 +0000297 return rc;
298
Steve French04fdabe2006-02-10 05:52:50 +0000299 buffer = (struct smb_hdr *)*request_buf;
Pavel Shilovsky88257362012-05-23 14:01:59 +0400300 buffer->Mid = get_next_mid(ses->server);
Steve French12b3b8f2006-02-09 21:12:47 +0000301 if (ses->capabilities & CAP_UNICODE)
302 buffer->Flags2 |= SMBFLG2_UNICODE;
Steve French04fdabe2006-02-10 05:52:50 +0000303 if (ses->capabilities & CAP_STATUS32)
Steve French12b3b8f2006-02-09 21:12:47 +0000304 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
305
306 /* uid, tid can stay at zero as set in header assemble */
307
Steve French50c2f752007-07-13 00:33:32 +0000308 /* BB add support for turning on the signing when
Steve French12b3b8f2006-02-09 21:12:47 +0000309 this function is used after 1st of session setup requests */
310
311 return rc;
312}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313
314/* If the return code is zero, this function must fill in request_buf pointer */
315static int
Steve French96daf2b2011-05-27 04:34:02 +0000316__smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400317 void **request_buf, void **response_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319 *request_buf = cifs_buf_get();
320 if (*request_buf == NULL) {
321 /* BB should we add a retry in here if not a writepage? */
322 return -ENOMEM;
323 }
324 /* Although the original thought was we needed the response buf for */
325 /* potential retries of smb operations it turns out we can determine */
326 /* from the mid flags when the request buffer can be resent without */
327 /* having to use a second distinct buffer for the response */
Steve French790fe572007-07-07 19:25:05 +0000328 if (response_buf)
Steve French50c2f752007-07-13 00:33:32 +0000329 *response_buf = *request_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330
331 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000332 wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333
Steve French790fe572007-07-07 19:25:05 +0000334 if (tcon != NULL)
335 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700336
Jeff Laytonf5695992010-09-29 15:27:08 -0400337 return 0;
338}
339
340/* If the return code is zero, this function must fill in request_buf pointer */
341static int
Steve French96daf2b2011-05-27 04:34:02 +0000342smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400343 void **request_buf, void **response_buf)
344{
345 int rc;
346
347 rc = cifs_reconnect_tcon(tcon, smb_command);
348 if (rc)
349 return rc;
350
351 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
352}
353
354static int
Steve French96daf2b2011-05-27 04:34:02 +0000355smb_init_no_reconnect(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400356 void **request_buf, void **response_buf)
357{
358 if (tcon->ses->need_reconnect || tcon->need_reconnect)
359 return -EHOSTDOWN;
360
361 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362}
363
Steve French50c2f752007-07-13 00:33:32 +0000364static int validate_t2(struct smb_t2_rsp *pSMB)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365{
Jeff Layton12df83c2011-01-20 13:36:51 -0500366 unsigned int total_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367
Jeff Layton12df83c2011-01-20 13:36:51 -0500368 /* check for plausible wct */
369 if (pSMB->hdr.WordCount < 10)
370 goto vt2_err;
371
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 /* check for parm and data offset going beyond end of smb */
Jeff Layton12df83c2011-01-20 13:36:51 -0500373 if (get_unaligned_le16(&pSMB->t2_rsp.ParameterOffset) > 1024 ||
374 get_unaligned_le16(&pSMB->t2_rsp.DataOffset) > 1024)
375 goto vt2_err;
376
Jeff Layton12df83c2011-01-20 13:36:51 -0500377 total_size = get_unaligned_le16(&pSMB->t2_rsp.ParameterCount);
378 if (total_size >= 512)
379 goto vt2_err;
380
Jeff Laytonfd5707e2011-03-31 17:22:07 -0400381 /* check that bcc is at least as big as parms + data, and that it is
382 * less than negotiated smb buffer
383 */
Jeff Layton12df83c2011-01-20 13:36:51 -0500384 total_size += get_unaligned_le16(&pSMB->t2_rsp.DataCount);
385 if (total_size > get_bcc(&pSMB->hdr) ||
386 total_size >= CIFSMaxBufSize + MAX_CIFS_HDR_SIZE)
387 goto vt2_err;
388
389 return 0;
390vt2_err:
Steve French50c2f752007-07-13 00:33:32 +0000391 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 sizeof(struct smb_t2_rsp) + 16);
Jeff Layton12df83c2011-01-20 13:36:51 -0500393 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394}
Jeff Layton690c5222011-01-20 13:36:51 -0500395
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396int
Pavel Shilovsky286170a2012-05-25 10:43:58 +0400397CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398{
399 NEGOTIATE_REQ *pSMB;
400 NEGOTIATE_RSP *pSMBr;
401 int rc = 0;
402 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000403 int i;
Steve French50c2f752007-07-13 00:33:32 +0000404 struct TCP_Server_Info *server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 u16 count;
Steve French750d1152006-06-27 06:28:30 +0000406 unsigned int secFlags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407
Steve French790fe572007-07-07 19:25:05 +0000408 if (ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409 server = ses->server;
410 else {
411 rc = -EIO;
412 return rc;
413 }
414 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
415 (void **) &pSMB, (void **) &pSMBr);
416 if (rc)
417 return rc;
Steve French750d1152006-06-27 06:28:30 +0000418
419 /* if any of auth flags (ie not sign or seal) are overriden use them */
Steve French790fe572007-07-07 19:25:05 +0000420 if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
Steve French762e5ab2007-06-28 18:41:42 +0000421 secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
Steve French750d1152006-06-27 06:28:30 +0000422 else /* if override flags set only sign/seal OR them with global auth */
Jeff Layton04912d62010-04-24 07:57:45 -0400423 secFlags = global_secflags | ses->overrideSecFlg;
Steve French750d1152006-06-27 06:28:30 +0000424
Joe Perchesb6b38f72010-04-21 03:50:45 +0000425 cFYI(1, "secFlags 0x%x", secFlags);
Steve Frenchf40c5622006-06-28 00:13:38 +0000426
Pavel Shilovsky88257362012-05-23 14:01:59 +0400427 pSMB->hdr.Mid = get_next_mid(server);
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000428 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
Steve Frencha0136892007-10-04 20:05:09 +0000429
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000430 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
Steve French254e55e2006-06-04 05:53:15 +0000431 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Steve Frencha0136892007-10-04 20:05:09 +0000432 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000433 cFYI(1, "Kerberos only mechanism, enable extended security");
Steve Frencha0136892007-10-04 20:05:09 +0000434 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Jeff Laytonb4d6fcf2011-01-07 11:30:28 -0500435 } else if ((secFlags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP)
Steve Frenchac683922009-05-06 04:16:04 +0000436 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
437 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_NTLMSSP) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000438 cFYI(1, "NTLMSSP only mechanism, enable extended security");
Steve Frenchac683922009-05-06 04:16:04 +0000439 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
440 }
Steve French50c2f752007-07-13 00:33:32 +0000441
Steve French39798772006-05-31 22:40:51 +0000442 count = 0;
Steve French50c2f752007-07-13 00:33:32 +0000443 for (i = 0; i < CIFS_NUM_PROT; i++) {
Steve French39798772006-05-31 22:40:51 +0000444 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
445 count += strlen(protocols[i].name) + 1;
446 /* null at end of source and target buffers anyway */
447 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000448 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449 pSMB->ByteCount = cpu_to_le16(count);
450
451 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
452 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French50c2f752007-07-13 00:33:32 +0000453 if (rc != 0)
Steve French254e55e2006-06-04 05:53:15 +0000454 goto neg_err_exit;
455
Jeff Layton9bf67e52010-04-24 07:57:46 -0400456 server->dialect = le16_to_cpu(pSMBr->DialectIndex);
457 cFYI(1, "Dialect: %d", server->dialect);
Steve French254e55e2006-06-04 05:53:15 +0000458 /* Check wct = 1 error case */
Jeff Layton9bf67e52010-04-24 07:57:46 -0400459 if ((pSMBr->hdr.WordCount < 13) || (server->dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000460 /* core returns wct = 1, but we do not ask for core - otherwise
Steve French50c2f752007-07-13 00:33:32 +0000461 small wct just comes when dialect index is -1 indicating we
Steve French254e55e2006-06-04 05:53:15 +0000462 could not negotiate a common dialect */
463 rc = -EOPNOTSUPP;
464 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000465#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French790fe572007-07-07 19:25:05 +0000466 } else if ((pSMBr->hdr.WordCount == 13)
Jeff Layton9bf67e52010-04-24 07:57:46 -0400467 && ((server->dialect == LANMAN_PROT)
468 || (server->dialect == LANMAN2_PROT))) {
Steve Frenchb815f1e52006-10-02 05:53:29 +0000469 __s16 tmp;
Steve French50c2f752007-07-13 00:33:32 +0000470 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
Steve French254e55e2006-06-04 05:53:15 +0000471
Steve French790fe572007-07-07 19:25:05 +0000472 if ((secFlags & CIFSSEC_MAY_LANMAN) ||
Steve French750d1152006-06-27 06:28:30 +0000473 (secFlags & CIFSSEC_MAY_PLNTXT))
Steve French254e55e2006-06-04 05:53:15 +0000474 server->secType = LANMAN;
475 else {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000476 cERROR(1, "mount failed weak security disabled"
477 " in /proc/fs/cifs/SecurityFlags");
Steve French39798772006-05-31 22:40:51 +0000478 rc = -EOPNOTSUPP;
479 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000480 }
Pavel Shilovsky286170a2012-05-25 10:43:58 +0400481 server->sec_mode = le16_to_cpu(rsp->SecurityMode);
Pavel Shilovsky10b9b982012-03-20 12:55:09 +0300482 server->maxReq = min_t(unsigned int,
483 le16_to_cpu(rsp->MaxMpxCount),
484 cifs_max_pending);
Pavel Shilovsky45275782012-05-17 17:53:29 +0400485 set_credits(server, server->maxReq);
Jeff Laytonc974bef2011-10-11 06:41:32 -0400486 server->maxBuf = le16_to_cpu(rsp->MaxBufSize);
Steve Frencheca6acf2009-02-20 05:43:09 +0000487 server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
Steve French254e55e2006-06-04 05:53:15 +0000488 /* even though we do not use raw we might as well set this
489 accurately, in case we ever find a need for it */
Steve French790fe572007-07-07 19:25:05 +0000490 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
Steve Frencheca6acf2009-02-20 05:43:09 +0000491 server->max_rw = 0xFF00;
Steve French254e55e2006-06-04 05:53:15 +0000492 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
493 } else {
Steve Frencheca6acf2009-02-20 05:43:09 +0000494 server->max_rw = 0;/* do not need to use raw anyway */
Steve French254e55e2006-06-04 05:53:15 +0000495 server->capabilities = CAP_MPX_MODE;
496 }
Steve Frenchb815f1e52006-10-02 05:53:29 +0000497 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
Steve French1a70d652006-10-02 05:59:18 +0000498 if (tmp == -1) {
Steve French25ee4a92006-09-30 00:54:23 +0000499 /* OS/2 often does not set timezone therefore
500 * we must use server time to calc time zone.
Steve Frenchb815f1e52006-10-02 05:53:29 +0000501 * Could deviate slightly from the right zone.
502 * Smallest defined timezone difference is 15 minutes
503 * (i.e. Nepal). Rounding up/down is done to match
504 * this requirement.
Steve French25ee4a92006-09-30 00:54:23 +0000505 */
Steve Frenchb815f1e52006-10-02 05:53:29 +0000506 int val, seconds, remain, result;
Steve French25ee4a92006-09-30 00:54:23 +0000507 struct timespec ts, utc;
508 utc = CURRENT_TIME;
Jeff Laytonc4a2c082009-05-27 09:37:33 -0400509 ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
510 rsp->SrvTime.Time, 0);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000511 cFYI(1, "SrvTime %d sec since 1970 (utc: %d) diff: %d",
Steve French50c2f752007-07-13 00:33:32 +0000512 (int)ts.tv_sec, (int)utc.tv_sec,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000513 (int)(utc.tv_sec - ts.tv_sec));
Steve Frenchb815f1e52006-10-02 05:53:29 +0000514 val = (int)(utc.tv_sec - ts.tv_sec);
Andre Haupt8594c152007-08-30 20:18:41 +0000515 seconds = abs(val);
Steve French947a5062006-10-02 05:55:25 +0000516 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
Steve Frenchb815f1e52006-10-02 05:53:29 +0000517 remain = seconds % MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000518 if (remain >= (MIN_TZ_ADJ / 2))
Steve Frenchb815f1e52006-10-02 05:53:29 +0000519 result += MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000520 if (val < 0)
Steve Frenchad7a2922008-02-07 23:25:02 +0000521 result = -result;
Steve Frenchb815f1e52006-10-02 05:53:29 +0000522 server->timeAdj = result;
Steve French25ee4a92006-09-30 00:54:23 +0000523 } else {
Steve Frenchb815f1e52006-10-02 05:53:29 +0000524 server->timeAdj = (int)tmp;
525 server->timeAdj *= 60; /* also in seconds */
Steve French25ee4a92006-09-30 00:54:23 +0000526 }
Joe Perchesb6b38f72010-04-21 03:50:45 +0000527 cFYI(1, "server->timeAdj: %d seconds", server->timeAdj);
Steve French25ee4a92006-09-30 00:54:23 +0000528
Steve French39798772006-05-31 22:40:51 +0000529
Steve French254e55e2006-06-04 05:53:15 +0000530 /* BB get server time for time conversions and add
Steve French50c2f752007-07-13 00:33:32 +0000531 code to use it and timezone since this is not UTC */
Steve French39798772006-05-31 22:40:51 +0000532
Steve French50c2f752007-07-13 00:33:32 +0000533 if (rsp->EncryptionKeyLength ==
Steve French25ee4a92006-09-30 00:54:23 +0000534 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500535 memcpy(ses->server->cryptkey, rsp->EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000536 CIFS_CRYPTO_KEY_SIZE);
Steve French96daf2b2011-05-27 04:34:02 +0000537 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
Steve French254e55e2006-06-04 05:53:15 +0000538 rc = -EIO; /* need cryptkey unless plain text */
539 goto neg_err_exit;
540 }
Steve French39798772006-05-31 22:40:51 +0000541
Steve Frenchf19159d2010-04-21 04:12:10 +0000542 cFYI(1, "LANMAN negotiated");
Steve French254e55e2006-06-04 05:53:15 +0000543 /* we will not end up setting signing flags - as no signing
544 was in LANMAN and server did not return the flags on */
545 goto signing_check;
Steve French7c7b25b2006-06-01 19:20:10 +0000546#else /* weak security disabled */
Steve French790fe572007-07-07 19:25:05 +0000547 } else if (pSMBr->hdr.WordCount == 13) {
Steve Frenchf19159d2010-04-21 04:12:10 +0000548 cERROR(1, "mount failed, cifs module not built "
549 "with CIFS_WEAK_PW_HASH support");
Dan Carpenter8212cf72010-03-15 11:22:26 +0300550 rc = -EOPNOTSUPP;
Steve French7c7b25b2006-06-01 19:20:10 +0000551#endif /* WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000552 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000553 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000554 /* unknown wct */
555 rc = -EOPNOTSUPP;
556 goto neg_err_exit;
557 }
558 /* else wct == 17 NTLM */
Steve French96daf2b2011-05-27 04:34:02 +0000559 server->sec_mode = pSMBr->SecurityMode;
560 if ((server->sec_mode & SECMODE_USER) == 0)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000561 cFYI(1, "share mode security");
Steve French39798772006-05-31 22:40:51 +0000562
Steve French96daf2b2011-05-27 04:34:02 +0000563 if ((server->sec_mode & SECMODE_PW_ENCRYPT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000564#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French750d1152006-06-27 06:28:30 +0000565 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000566#endif /* CIFS_WEAK_PW_HASH */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000567 cERROR(1, "Server requests plain text password"
568 " but client support disabled");
Steve French9312f672006-06-04 22:21:07 +0000569
Steve French790fe572007-07-07 19:25:05 +0000570 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
Steve French254e55e2006-06-04 05:53:15 +0000571 server->secType = NTLMv2;
Steve French790fe572007-07-07 19:25:05 +0000572 else if (secFlags & CIFSSEC_MAY_NTLM)
Steve French254e55e2006-06-04 05:53:15 +0000573 server->secType = NTLM;
Steve French790fe572007-07-07 19:25:05 +0000574 else if (secFlags & CIFSSEC_MAY_NTLMV2)
Steve Frenchf40c5622006-06-28 00:13:38 +0000575 server->secType = NTLMv2;
Steve Frencha0136892007-10-04 20:05:09 +0000576 else if (secFlags & CIFSSEC_MAY_KRB5)
577 server->secType = Kerberos;
Steve Frenchac683922009-05-06 04:16:04 +0000578 else if (secFlags & CIFSSEC_MAY_NTLMSSP)
Steve Frenchf46c7232009-06-25 03:04:20 +0000579 server->secType = RawNTLMSSP;
Steve Frencha0136892007-10-04 20:05:09 +0000580 else if (secFlags & CIFSSEC_MAY_LANMAN)
581 server->secType = LANMAN;
Steve Frencha0136892007-10-04 20:05:09 +0000582 else {
583 rc = -EOPNOTSUPP;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000584 cERROR(1, "Invalid security type");
Steve Frencha0136892007-10-04 20:05:09 +0000585 goto neg_err_exit;
586 }
587 /* else ... any others ...? */
Steve French7c7b25b2006-06-01 19:20:10 +0000588
Steve French254e55e2006-06-04 05:53:15 +0000589 /* one byte, so no need to convert this or EncryptionKeyLen from
590 little endian */
Pavel Shilovsky10b9b982012-03-20 12:55:09 +0300591 server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount),
592 cifs_max_pending);
Pavel Shilovsky45275782012-05-17 17:53:29 +0400593 set_credits(server, server->maxReq);
Steve French254e55e2006-06-04 05:53:15 +0000594 /* probably no need to store and check maxvcs */
Jeff Laytonc974bef2011-10-11 06:41:32 -0400595 server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize);
Steve Frencheca6acf2009-02-20 05:43:09 +0000596 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000597 cFYI(DBG2, "Max buf = %d", ses->server->maxBuf);
Steve French254e55e2006-06-04 05:53:15 +0000598 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e52006-10-02 05:53:29 +0000599 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
600 server->timeAdj *= 60;
Steve French254e55e2006-06-04 05:53:15 +0000601 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500602 memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000603 CIFS_CRYPTO_KEY_SIZE);
Steve French07cc6cf2011-05-27 04:12:29 +0000604 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC ||
605 server->capabilities & CAP_EXTENDED_SECURITY) &&
606 (pSMBr->EncryptionKeyLength == 0)) {
Steve French254e55e2006-06-04 05:53:15 +0000607 /* decode security blob */
Jeff Layton820a8032011-05-04 08:05:26 -0400608 count = get_bcc(&pSMBr->hdr);
Jeff Laytone187e442007-10-16 17:10:44 +0000609 if (count < 16) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 rc = -EIO;
Jeff Laytone187e442007-10-16 17:10:44 +0000611 goto neg_err_exit;
612 }
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530613 spin_lock(&cifs_tcp_ses_lock);
Jeff Laytone7ddee92008-11-14 13:44:38 -0500614 if (server->srv_count > 1) {
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530615 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000616 if (memcmp(server->server_GUID,
617 pSMBr->u.extended_response.
618 GUID, 16) != 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000619 cFYI(1, "server UID changed");
Steve French254e55e2006-06-04 05:53:15 +0000620 memcpy(server->server_GUID,
Jeff Laytone187e442007-10-16 17:10:44 +0000621 pSMBr->u.extended_response.GUID,
622 16);
623 }
Jeff Laytone7ddee92008-11-14 13:44:38 -0500624 } else {
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530625 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000626 memcpy(server->server_GUID,
627 pSMBr->u.extended_response.GUID, 16);
Jeff Laytone7ddee92008-11-14 13:44:38 -0500628 }
Jeff Laytone187e442007-10-16 17:10:44 +0000629
630 if (count == 16) {
631 server->secType = RawNTLMSSP;
Steve French254e55e2006-06-04 05:53:15 +0000632 } else {
633 rc = decode_negTokenInit(pSMBr->u.extended_response.
Jeff Layton26efa0b2010-04-24 07:57:49 -0400634 SecurityBlob, count - 16,
635 server);
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000636 if (rc == 1)
Jeff Laytone5459372007-11-03 05:11:06 +0000637 rc = 0;
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000638 else
Steve French254e55e2006-06-04 05:53:15 +0000639 rc = -EINVAL;
Shirish Pargaonkar2b149f12010-09-18 22:02:18 -0500640 if (server->secType == Kerberos) {
641 if (!server->sec_kerberos &&
642 !server->sec_mskerberos)
643 rc = -EOPNOTSUPP;
644 } else if (server->secType == RawNTLMSSP) {
645 if (!server->sec_ntlmssp)
646 rc = -EOPNOTSUPP;
647 } else
648 rc = -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649 }
Steve French96daf2b2011-05-27 04:34:02 +0000650 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
Steve French07cc6cf2011-05-27 04:12:29 +0000651 rc = -EIO; /* no crypt key only if plain text pwd */
652 goto neg_err_exit;
Steve French254e55e2006-06-04 05:53:15 +0000653 } else
654 server->capabilities &= ~CAP_EXTENDED_SECURITY;
655
Steve French6344a422006-06-12 04:18:35 +0000656#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French254e55e2006-06-04 05:53:15 +0000657signing_check:
Steve French6344a422006-06-12 04:18:35 +0000658#endif
Steve French762e5ab2007-06-28 18:41:42 +0000659 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
660 /* MUST_SIGN already includes the MAY_SIGN FLAG
661 so if this is zero it means that signing is disabled */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000662 cFYI(1, "Signing disabled");
Steve French96daf2b2011-05-27 04:34:02 +0000663 if (server->sec_mode & SECMODE_SIGN_REQUIRED) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000664 cERROR(1, "Server requires "
Jeff Layton7111d212007-10-16 16:50:25 +0000665 "packet signing to be enabled in "
Joe Perchesb6b38f72010-04-21 03:50:45 +0000666 "/proc/fs/cifs/SecurityFlags.");
Steve Frenchabb63d62007-10-18 02:58:40 +0000667 rc = -EOPNOTSUPP;
668 }
Steve French96daf2b2011-05-27 04:34:02 +0000669 server->sec_mode &=
Steve French254e55e2006-06-04 05:53:15 +0000670 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Steve French762e5ab2007-06-28 18:41:42 +0000671 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
672 /* signing required */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000673 cFYI(1, "Must sign - secFlags 0x%x", secFlags);
Steve French96daf2b2011-05-27 04:34:02 +0000674 if ((server->sec_mode &
Steve French762e5ab2007-06-28 18:41:42 +0000675 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000676 cERROR(1, "signing required but server lacks support");
Jeff38c10a12007-07-06 21:10:07 +0000677 rc = -EOPNOTSUPP;
Steve French762e5ab2007-06-28 18:41:42 +0000678 } else
Steve French96daf2b2011-05-27 04:34:02 +0000679 server->sec_mode |= SECMODE_SIGN_REQUIRED;
Steve French762e5ab2007-06-28 18:41:42 +0000680 } else {
681 /* signing optional ie CIFSSEC_MAY_SIGN */
Steve French96daf2b2011-05-27 04:34:02 +0000682 if ((server->sec_mode & SECMODE_SIGN_REQUIRED) == 0)
683 server->sec_mode &=
Steve French254e55e2006-06-04 05:53:15 +0000684 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 }
Steve French50c2f752007-07-13 00:33:32 +0000686
687neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700688 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000689
Joe Perchesb6b38f72010-04-21 03:50:45 +0000690 cFYI(1, "negprot rc %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 return rc;
692}
693
694int
Pavel Shilovsky2e6e02a2012-05-25 11:11:39 +0400695CIFSSMBTDis(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696{
697 struct smb_hdr *smb_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699
Joe Perchesb6b38f72010-04-21 03:50:45 +0000700 cFYI(1, "In tree disconnect");
Jeff Laytonf1987b42008-11-15 11:12:47 -0500701
702 /* BB: do we need to check this? These should never be NULL. */
703 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
704 return -EIO;
705
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 /*
Jeff Laytonf1987b42008-11-15 11:12:47 -0500707 * No need to return error on this operation if tid invalidated and
708 * closed on server already e.g. due to tcp session crashing. Also,
709 * the tcon is no longer on the list, so no need to take lock before
710 * checking this.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 */
Steve French268875b2009-06-25 00:29:21 +0000712 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
Steve French50c2f752007-07-13 00:33:32 +0000713 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714
Steve French50c2f752007-07-13 00:33:32 +0000715 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700716 (void **)&smb_buffer);
Jeff Laytonf1987b42008-11-15 11:12:47 -0500717 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 return rc;
Steve French133672e2007-11-13 22:41:37 +0000719
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400720 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)smb_buffer, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000722 cFYI(1, "Tree disconnect failed %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723
Steve French50c2f752007-07-13 00:33:32 +0000724 /* No need to return error on this operation if tid invalidated and
Jeff Laytonf1987b42008-11-15 11:12:47 -0500725 closed on server already e.g. due to tcp session crashing */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 if (rc == -EAGAIN)
727 rc = 0;
728
729 return rc;
730}
731
Jeff Layton766fdbb2011-01-11 07:24:21 -0500732/*
733 * This is a no-op for now. We're not really interested in the reply, but
734 * rather in the fact that the server sent one and that server->lstrp
735 * gets updated.
736 *
737 * FIXME: maybe we should consider checking that the reply matches request?
738 */
739static void
740cifs_echo_callback(struct mid_q_entry *mid)
741{
742 struct TCP_Server_Info *server = mid->callback_data;
743
744 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +0400745 add_credits(server, 1, CIFS_ECHO_OP);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500746}
747
748int
749CIFSSMBEcho(struct TCP_Server_Info *server)
750{
751 ECHO_REQ *smb;
752 int rc = 0;
Jeff Laytonfcc31cb2011-05-19 16:22:53 -0400753 struct kvec iov;
Jeff Layton766fdbb2011-01-11 07:24:21 -0500754
755 cFYI(1, "In echo request");
756
757 rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
758 if (rc)
759 return rc;
760
761 /* set up echo request */
Steve French5443d132011-03-13 05:08:25 +0000762 smb->hdr.Tid = 0xffff;
Jeff Layton99d86c82011-01-20 21:19:25 -0500763 smb->hdr.WordCount = 1;
764 put_unaligned_le16(1, &smb->EchoCount);
Jeff Layton820a8032011-05-04 08:05:26 -0400765 put_bcc(1, &smb->hdr);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500766 smb->Data[0] = 'a';
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000767 inc_rfc1001_len(smb, 3);
Jeff Laytonfcc31cb2011-05-19 16:22:53 -0400768 iov.iov_base = smb;
769 iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
Jeff Layton766fdbb2011-01-11 07:24:21 -0500770
Jeff Layton44d22d82011-10-19 15:29:49 -0400771 rc = cifs_call_async(server, &iov, 1, NULL, cifs_echo_callback,
Pavel Shilovskya891f0f2012-05-23 16:14:34 +0400772 server, CIFS_ASYNC_OP | CIFS_ECHO_OP);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500773 if (rc)
774 cFYI(1, "Echo request failed: %d", rc);
775
776 cifs_small_buf_release(smb);
777
778 return rc;
779}
780
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781int
Pavel Shilovsky58c45c52012-05-25 10:54:49 +0400782CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 LOGOFF_ANDX_REQ *pSMB;
785 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786
Joe Perchesb6b38f72010-04-21 03:50:45 +0000787 cFYI(1, "In SMBLogoff for session disconnect");
Jeff Layton14fbf502008-11-14 13:53:46 -0500788
789 /*
790 * BB: do we need to check validity of ses and server? They should
791 * always be valid since we have an active reference. If not, that
792 * should probably be a BUG()
793 */
794 if (!ses || !ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 return -EIO;
796
Steve Frenchd7b619c2010-02-25 05:36:46 +0000797 mutex_lock(&ses->session_mutex);
Steve French3b795212008-11-13 19:45:32 +0000798 if (ses->need_reconnect)
799 goto session_already_dead; /* no need to send SMBlogoff if uid
800 already closed due to reconnect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
802 if (rc) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000803 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 return rc;
805 }
806
Pavel Shilovsky88257362012-05-23 14:01:59 +0400807 pSMB->hdr.Mid = get_next_mid(ses->server);
Steve French1982c342005-08-17 12:38:22 -0700808
Steve French96daf2b2011-05-27 04:34:02 +0000809 if (ses->server->sec_mode &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
811 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812
813 pSMB->hdr.Uid = ses->Suid;
814
815 pSMB->AndXCommand = 0xFF;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400816 rc = SendReceiveNoRsp(xid, ses, (char *) pSMB, 0);
Steve French3b795212008-11-13 19:45:32 +0000817session_already_dead:
Steve Frenchd7b619c2010-02-25 05:36:46 +0000818 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819
820 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000821 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 error */
823 if (rc == -EAGAIN)
824 rc = 0;
825 return rc;
826}
827
828int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400829CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
830 const char *fileName, __u16 type,
831 const struct nls_table *nls_codepage, int remap)
Steve French2d785a52007-07-15 01:48:57 +0000832{
833 TRANSACTION2_SPI_REQ *pSMB = NULL;
834 TRANSACTION2_SPI_RSP *pSMBr = NULL;
835 struct unlink_psx_rq *pRqD;
836 int name_len;
837 int rc = 0;
838 int bytes_returned = 0;
839 __u16 params, param_offset, offset, byte_count;
840
Joe Perchesb6b38f72010-04-21 03:50:45 +0000841 cFYI(1, "In POSIX delete");
Steve French2d785a52007-07-15 01:48:57 +0000842PsxDelete:
843 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
844 (void **) &pSMBr);
845 if (rc)
846 return rc;
847
848 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
849 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -0600850 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
851 PATH_MAX, nls_codepage, remap);
Steve French2d785a52007-07-15 01:48:57 +0000852 name_len++; /* trailing null */
853 name_len *= 2;
854 } else { /* BB add path length overrun check */
855 name_len = strnlen(fileName, PATH_MAX);
856 name_len++; /* trailing null */
857 strncpy(pSMB->FileName, fileName, name_len);
858 }
859
860 params = 6 + name_len;
861 pSMB->MaxParameterCount = cpu_to_le16(2);
862 pSMB->MaxDataCount = 0; /* BB double check this with jra */
863 pSMB->MaxSetupCount = 0;
864 pSMB->Reserved = 0;
865 pSMB->Flags = 0;
866 pSMB->Timeout = 0;
867 pSMB->Reserved2 = 0;
868 param_offset = offsetof(struct smb_com_transaction2_spi_req,
869 InformationLevel) - 4;
870 offset = param_offset + params;
871
872 /* Setup pointer to Request Data (inode type) */
873 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
874 pRqD->type = cpu_to_le16(type);
875 pSMB->ParameterOffset = cpu_to_le16(param_offset);
876 pSMB->DataOffset = cpu_to_le16(offset);
877 pSMB->SetupCount = 1;
878 pSMB->Reserved3 = 0;
879 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
880 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
881
882 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
883 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
884 pSMB->ParameterCount = cpu_to_le16(params);
885 pSMB->TotalParameterCount = pSMB->ParameterCount;
886 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
887 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000888 inc_rfc1001_len(pSMB, byte_count);
Steve French2d785a52007-07-15 01:48:57 +0000889 pSMB->ByteCount = cpu_to_le16(byte_count);
890 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
891 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000892 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000893 cFYI(1, "Posix delete returned %d", rc);
Steve French2d785a52007-07-15 01:48:57 +0000894 cifs_buf_release(pSMB);
895
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400896 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve French2d785a52007-07-15 01:48:57 +0000897
898 if (rc == -EAGAIN)
899 goto PsxDelete;
900
901 return rc;
902}
903
904int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400905CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon,
906 const char *fileName, const struct nls_table *nls_codepage,
907 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908{
909 DELETE_FILE_REQ *pSMB = NULL;
910 DELETE_FILE_RSP *pSMBr = NULL;
911 int rc = 0;
912 int bytes_returned;
913 int name_len;
914
915DelFileRetry:
916 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
917 (void **) &pSMBr);
918 if (rc)
919 return rc;
920
921 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
922 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -0600923 cifsConvertToUTF16((__le16 *) pSMB->fileName, fileName,
924 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925 name_len++; /* trailing null */
926 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700927 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928 name_len = strnlen(fileName, PATH_MAX);
929 name_len++; /* trailing null */
930 strncpy(pSMB->fileName, fileName, name_len);
931 }
932 pSMB->SearchAttributes =
933 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
934 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000935 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936 pSMB->ByteCount = cpu_to_le16(name_len + 1);
937 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
938 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400939 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000940 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000941 cFYI(1, "Error in RMFile = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942
943 cifs_buf_release(pSMB);
944 if (rc == -EAGAIN)
945 goto DelFileRetry;
946
947 return rc;
948}
949
950int
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400951CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
952 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953{
954 DELETE_DIRECTORY_REQ *pSMB = NULL;
955 DELETE_DIRECTORY_RSP *pSMBr = NULL;
956 int rc = 0;
957 int bytes_returned;
958 int name_len;
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400959 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960
Joe Perchesb6b38f72010-04-21 03:50:45 +0000961 cFYI(1, "In CIFSSMBRmDir");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962RmDirRetry:
963 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
964 (void **) &pSMBr);
965 if (rc)
966 return rc;
967
968 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400969 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
970 PATH_MAX, cifs_sb->local_nls,
971 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972 name_len++; /* trailing null */
973 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700974 } else { /* BB improve check for buffer overruns BB */
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400975 name_len = strnlen(name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 name_len++; /* trailing null */
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400977 strncpy(pSMB->DirName, name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 }
979
980 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000981 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 pSMB->ByteCount = cpu_to_le16(name_len + 1);
983 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
984 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400985 cifs_stats_inc(&tcon->stats.cifs_stats.num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000986 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000987 cFYI(1, "Error in RMDir = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988
989 cifs_buf_release(pSMB);
990 if (rc == -EAGAIN)
991 goto RmDirRetry;
992 return rc;
993}
994
995int
Pavel Shilovskyf4367202012-03-17 11:41:12 +0300996CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
997 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998{
999 int rc = 0;
1000 CREATE_DIRECTORY_REQ *pSMB = NULL;
1001 CREATE_DIRECTORY_RSP *pSMBr = NULL;
1002 int bytes_returned;
1003 int name_len;
Pavel Shilovskyf4367202012-03-17 11:41:12 +03001004 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005
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,
Pavel Shilovskyf4367202012-03-17 11:41:12 +03001015 PATH_MAX, cifs_sb->local_nls,
1016 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 name_len++; /* trailing null */
1018 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -07001019 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 name_len = strnlen(name, PATH_MAX);
1021 name_len++; /* trailing null */
1022 strncpy(pSMB->DirName, name, name_len);
1023 }
1024
1025 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001026 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027 pSMB->ByteCount = cpu_to_le16(name_len + 1);
1028 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1029 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001030 cifs_stats_inc(&tcon->stats.cifs_stats.num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +00001031 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001032 cFYI(1, "Error in Mkdir = %d", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07001033
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034 cifs_buf_release(pSMB);
1035 if (rc == -EAGAIN)
1036 goto MkDirRetry;
1037 return rc;
1038}
1039
Steve French2dd29d32007-04-23 22:07:35 +00001040int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001041CIFSPOSIXCreate(const unsigned int xid, struct cifs_tcon *tcon,
1042 __u32 posix_flags, __u64 mode, __u16 *netfid,
1043 FILE_UNIX_BASIC_INFO *pRetData, __u32 *pOplock,
1044 const char *name, const struct nls_table *nls_codepage,
1045 int remap)
Steve French2dd29d32007-04-23 22:07:35 +00001046{
1047 TRANSACTION2_SPI_REQ *pSMB = NULL;
1048 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1049 int name_len;
1050 int rc = 0;
1051 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001052 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +00001053 OPEN_PSX_REQ *pdata;
1054 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +00001055
Joe Perchesb6b38f72010-04-21 03:50:45 +00001056 cFYI(1, "In POSIX Create");
Steve French2dd29d32007-04-23 22:07:35 +00001057PsxCreat:
1058 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1059 (void **) &pSMBr);
1060 if (rc)
1061 return rc;
1062
1063 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1064 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001065 cifsConvertToUTF16((__le16 *) pSMB->FileName, name,
1066 PATH_MAX, nls_codepage, remap);
Steve French2dd29d32007-04-23 22:07:35 +00001067 name_len++; /* trailing null */
1068 name_len *= 2;
1069 } else { /* BB improve the check for buffer overruns BB */
1070 name_len = strnlen(name, PATH_MAX);
1071 name_len++; /* trailing null */
1072 strncpy(pSMB->FileName, name, name_len);
1073 }
1074
1075 params = 6 + name_len;
1076 count = sizeof(OPEN_PSX_REQ);
1077 pSMB->MaxParameterCount = cpu_to_le16(2);
1078 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1079 pSMB->MaxSetupCount = 0;
1080 pSMB->Reserved = 0;
1081 pSMB->Flags = 0;
1082 pSMB->Timeout = 0;
1083 pSMB->Reserved2 = 0;
1084 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001085 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001086 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001087 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001088 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001089 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001090 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001091 pdata->OpenFlags = cpu_to_le32(*pOplock);
1092 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1093 pSMB->DataOffset = cpu_to_le16(offset);
1094 pSMB->SetupCount = 1;
1095 pSMB->Reserved3 = 0;
1096 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1097 byte_count = 3 /* pad */ + params + count;
1098
1099 pSMB->DataCount = cpu_to_le16(count);
1100 pSMB->ParameterCount = cpu_to_le16(params);
1101 pSMB->TotalDataCount = pSMB->DataCount;
1102 pSMB->TotalParameterCount = pSMB->ParameterCount;
1103 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1104 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001105 inc_rfc1001_len(pSMB, byte_count);
Steve French2dd29d32007-04-23 22:07:35 +00001106 pSMB->ByteCount = cpu_to_le16(byte_count);
1107 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1108 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1109 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001110 cFYI(1, "Posix create returned %d", rc);
Steve French2dd29d32007-04-23 22:07:35 +00001111 goto psx_create_err;
1112 }
1113
Joe Perchesb6b38f72010-04-21 03:50:45 +00001114 cFYI(1, "copying inode info");
Steve French2dd29d32007-04-23 22:07:35 +00001115 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1116
Jeff Layton820a8032011-05-04 08:05:26 -04001117 if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) {
Steve French2dd29d32007-04-23 22:07:35 +00001118 rc = -EIO; /* bad smb */
1119 goto psx_create_err;
1120 }
1121
1122 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001123 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001124 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001125
Steve French2dd29d32007-04-23 22:07:35 +00001126 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001127 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001128 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1129 /* Let caller know file was created so we can set the mode. */
1130 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001131 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001132 *pOplock |= CIFS_CREATE_ACTION;
1133 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001134 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1135 pRetData->Type = cpu_to_le32(-1); /* unknown */
Joe Perchesb6b38f72010-04-21 03:50:45 +00001136 cFYI(DBG2, "unknown type");
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001137 } else {
Jeff Layton820a8032011-05-04 08:05:26 -04001138 if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001139 + sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001140 cERROR(1, "Open response data too small");
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001141 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001142 goto psx_create_err;
1143 }
Steve French50c2f752007-07-13 00:33:32 +00001144 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001145 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001146 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001147 }
Steve French2dd29d32007-04-23 22:07:35 +00001148
1149psx_create_err:
1150 cifs_buf_release(pSMB);
1151
Steve French65bc98b2009-07-10 15:27:25 +00001152 if (posix_flags & SMB_O_DIRECTORY)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001153 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixmkdirs);
Steve French65bc98b2009-07-10 15:27:25 +00001154 else
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001155 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixopens);
Steve French2dd29d32007-04-23 22:07:35 +00001156
1157 if (rc == -EAGAIN)
1158 goto PsxCreat;
1159
Steve French50c2f752007-07-13 00:33:32 +00001160 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001161}
1162
Steve Frencha9d02ad2005-08-24 23:06:05 -07001163static __u16 convert_disposition(int disposition)
1164{
1165 __u16 ofun = 0;
1166
1167 switch (disposition) {
1168 case FILE_SUPERSEDE:
1169 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1170 break;
1171 case FILE_OPEN:
1172 ofun = SMBOPEN_OAPPEND;
1173 break;
1174 case FILE_CREATE:
1175 ofun = SMBOPEN_OCREATE;
1176 break;
1177 case FILE_OPEN_IF:
1178 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1179 break;
1180 case FILE_OVERWRITE:
1181 ofun = SMBOPEN_OTRUNC;
1182 break;
1183 case FILE_OVERWRITE_IF:
1184 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1185 break;
1186 default:
Joe Perchesb6b38f72010-04-21 03:50:45 +00001187 cFYI(1, "unknown disposition %d", disposition);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001188 ofun = SMBOPEN_OAPPEND; /* regular open */
1189 }
1190 return ofun;
1191}
1192
Jeff Layton35fc37d2008-05-14 10:22:03 -07001193static int
1194access_flags_to_smbopen_mode(const int access_flags)
1195{
1196 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1197
1198 if (masked_flags == GENERIC_READ)
1199 return SMBOPEN_READ;
1200 else if (masked_flags == GENERIC_WRITE)
1201 return SMBOPEN_WRITE;
1202
1203 /* just go for read/write */
1204 return SMBOPEN_READWRITE;
1205}
1206
Steve Frencha9d02ad2005-08-24 23:06:05 -07001207int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001208SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001209 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001210 const int access_flags, const int create_options, __u16 *netfid,
1211 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001212 const struct nls_table *nls_codepage, int remap)
1213{
1214 int rc = -EACCES;
1215 OPENX_REQ *pSMB = NULL;
1216 OPENX_RSP *pSMBr = NULL;
1217 int bytes_returned;
1218 int name_len;
1219 __u16 count;
1220
1221OldOpenRetry:
1222 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1223 (void **) &pSMBr);
1224 if (rc)
1225 return rc;
1226
1227 pSMB->AndXCommand = 0xFF; /* none */
1228
1229 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1230 count = 1; /* account for one byte pad to word boundary */
1231 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001232 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1233 fileName, PATH_MAX, nls_codepage, remap);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001234 name_len++; /* trailing null */
1235 name_len *= 2;
1236 } else { /* BB improve check for buffer overruns BB */
1237 count = 0; /* no pad */
1238 name_len = strnlen(fileName, PATH_MAX);
1239 name_len++; /* trailing null */
1240 strncpy(pSMB->fileName, fileName, name_len);
1241 }
1242 if (*pOplock & REQ_OPLOCK)
1243 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001244 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001245 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001246
Steve Frencha9d02ad2005-08-24 23:06:05 -07001247 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001248 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001249 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1250 /* set file as system file if special file such
1251 as fifo and server expecting SFU style and
1252 no Unix extensions */
1253
Steve French790fe572007-07-07 19:25:05 +00001254 if (create_options & CREATE_OPTION_SPECIAL)
1255 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001256 else /* BB FIXME BB */
1257 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001258
Jeff Layton67750fb2008-05-09 22:28:02 +00001259 if (create_options & CREATE_OPTION_READONLY)
1260 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001261
1262 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001263/* pSMB->CreateOptions = cpu_to_le32(create_options &
1264 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001265 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001266
1267 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001268 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001269 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001270 inc_rfc1001_len(pSMB, count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001271
1272 pSMB->ByteCount = cpu_to_le16(count);
1273 /* long_op set to 1 to allow for oplock break timeouts */
1274 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001275 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001276 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001277 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001278 cFYI(1, "Error in Open = %d", rc);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001279 } else {
1280 /* BB verify if wct == 15 */
1281
Steve French582d21e2008-05-13 04:54:12 +00001282/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001283
1284 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1285 /* Let caller know file was created so we can set the mode. */
1286 /* Do we care about the CreateAction in any other cases? */
1287 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001288/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001289 *pOplock |= CIFS_CREATE_ACTION; */
1290 /* BB FIXME END */
1291
Steve French790fe572007-07-07 19:25:05 +00001292 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001293 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1294 pfile_info->LastAccessTime = 0; /* BB fixme */
1295 pfile_info->LastWriteTime = 0; /* BB fixme */
1296 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001297 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001298 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001299 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001300 pfile_info->AllocationSize =
1301 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1302 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001303 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001304 pfile_info->DeletePending = 0;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001305 }
1306 }
1307
1308 cifs_buf_release(pSMB);
1309 if (rc == -EAGAIN)
1310 goto OldOpenRetry;
1311 return rc;
1312}
1313
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001315CIFSSMBOpen(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001317 const int access_flags, const int create_options, __u16 *netfid,
1318 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001319 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320{
1321 int rc = -EACCES;
1322 OPEN_REQ *pSMB = NULL;
1323 OPEN_RSP *pSMBr = NULL;
1324 int bytes_returned;
1325 int name_len;
1326 __u16 count;
1327
1328openRetry:
1329 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1330 (void **) &pSMBr);
1331 if (rc)
1332 return rc;
1333
1334 pSMB->AndXCommand = 0xFF; /* none */
1335
1336 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1337 count = 1; /* account for one byte pad to word boundary */
1338 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001339 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1340 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341 name_len++; /* trailing null */
1342 name_len *= 2;
1343 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001344 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345 count = 0; /* no pad */
1346 name_len = strnlen(fileName, PATH_MAX);
1347 name_len++; /* trailing null */
1348 pSMB->NameLength = cpu_to_le16(name_len);
1349 strncpy(pSMB->fileName, fileName, name_len);
1350 }
1351 if (*pOplock & REQ_OPLOCK)
1352 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001353 else if (*pOplock & REQ_BATCHOPLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1356 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -07001357 /* set file as system file if special file such
1358 as fifo and server expecting SFU style and
1359 no Unix extensions */
Steve French790fe572007-07-07 19:25:05 +00001360 if (create_options & CREATE_OPTION_SPECIAL)
Steve Frencheda3c0292005-07-21 15:20:28 -07001361 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1362 else
1363 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Jeff Layton67750fb2008-05-09 22:28:02 +00001364
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365 /* XP does not handle ATTR_POSIX_SEMANTICS */
1366 /* but it helps speed up case sensitive checks for other
1367 servers such as Samba */
1368 if (tcon->ses->capabilities & CAP_UNIX)
1369 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1370
Jeff Layton67750fb2008-05-09 22:28:02 +00001371 if (create_options & CREATE_OPTION_READONLY)
1372 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1373
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1375 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -07001376 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001377 /* BB Expirement with various impersonation levels and verify */
1378 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379 pSMB->SecurityFlags =
1380 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1381
1382 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001383 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384
1385 pSMB->ByteCount = cpu_to_le16(count);
1386 /* long_op set to 1 to allow for oplock break timeouts */
1387 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001388 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001389 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001391 cFYI(1, "Error in Open = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392 } else {
Steve French09d1db52005-04-28 22:41:08 -07001393 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1395 /* Let caller know file was created so we can set the mode. */
1396 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001397 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve French50c2f752007-07-13 00:33:32 +00001398 *pOplock |= CIFS_CREATE_ACTION;
Steve French790fe572007-07-07 19:25:05 +00001399 if (pfile_info) {
Steve French61e74802008-12-03 00:57:54 +00001400 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1401 36 /* CreationTime to Attributes */);
1402 /* the file_info buf is endian converted by caller */
1403 pfile_info->AllocationSize = pSMBr->AllocationSize;
1404 pfile_info->EndOfFile = pSMBr->EndOfFile;
1405 pfile_info->NumberOfLinks = cpu_to_le32(1);
1406 pfile_info->DeletePending = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001409
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410 cifs_buf_release(pSMB);
1411 if (rc == -EAGAIN)
1412 goto openRetry;
1413 return rc;
1414}
1415
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001416/*
1417 * Discard any remaining data in the current SMB. To do this, we borrow the
1418 * current bigbuf.
1419 */
1420static int
1421cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1422{
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001423 unsigned int rfclen = get_rfc1002_length(server->smallbuf);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001424 int remaining = rfclen + 4 - server->total_read;
1425 struct cifs_readdata *rdata = mid->callback_data;
1426
1427 while (remaining > 0) {
1428 int length;
1429
1430 length = cifs_read_from_socket(server, server->bigbuf,
1431 min_t(unsigned int, remaining,
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001432 CIFSMaxBufSize + MAX_HEADER_SIZE(server)));
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001433 if (length < 0)
1434 return length;
1435 server->total_read += length;
1436 remaining -= length;
1437 }
1438
1439 dequeue_mid(mid, rdata->result);
1440 return 0;
1441}
1442
1443static int
1444cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1445{
1446 int length, len;
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001447 unsigned int data_offset, data_len;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001448 struct cifs_readdata *rdata = mid->callback_data;
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001449 char *buf = server->smallbuf;
1450 unsigned int buflen = get_rfc1002_length(buf) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001451
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001452 cFYI(1, "%s: mid=%llu offset=%llu bytes=%u", __func__,
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001453 mid->mid, rdata->offset, rdata->bytes);
1454
1455 /*
1456 * read the rest of READ_RSP header (sans Data array), or whatever we
1457 * can if there's not enough data. At this point, we've read down to
1458 * the Mid.
1459 */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001460 len = min_t(unsigned int, buflen, server->vals->read_rsp_size) -
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001461 HEADER_SIZE(server) + 1;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001462
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001463 rdata->iov[0].iov_base = buf + HEADER_SIZE(server) - 1;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001464 rdata->iov[0].iov_len = len;
1465
1466 length = cifs_readv_from_socket(server, rdata->iov, 1, len);
1467 if (length < 0)
1468 return length;
1469 server->total_read += length;
1470
1471 /* Was the SMB read successful? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001472 rdata->result = server->ops->map_error(buf, false);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001473 if (rdata->result != 0) {
1474 cFYI(1, "%s: server returned error %d", __func__,
1475 rdata->result);
1476 return cifs_readv_discard(server, mid);
1477 }
1478
1479 /* Is there enough to get to the rest of the READ_RSP header? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001480 if (server->total_read < server->vals->read_rsp_size) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001481 cFYI(1, "%s: server returned short header. got=%u expected=%zu",
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001482 __func__, server->total_read,
1483 server->vals->read_rsp_size);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001484 rdata->result = -EIO;
1485 return cifs_readv_discard(server, mid);
1486 }
1487
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001488 data_offset = server->ops->read_data_offset(buf) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001489 if (data_offset < server->total_read) {
1490 /*
1491 * win2k8 sometimes sends an offset of 0 when the read
1492 * is beyond the EOF. Treat it as if the data starts just after
1493 * the header.
1494 */
1495 cFYI(1, "%s: data offset (%u) inside read response header",
1496 __func__, data_offset);
1497 data_offset = server->total_read;
1498 } else if (data_offset > MAX_CIFS_SMALL_BUFFER_SIZE) {
1499 /* data_offset is beyond the end of smallbuf */
1500 cFYI(1, "%s: data offset (%u) beyond end of smallbuf",
1501 __func__, data_offset);
1502 rdata->result = -EIO;
1503 return cifs_readv_discard(server, mid);
1504 }
1505
1506 cFYI(1, "%s: total_read=%u data_offset=%u", __func__,
1507 server->total_read, data_offset);
1508
1509 len = data_offset - server->total_read;
1510 if (len > 0) {
1511 /* read any junk before data into the rest of smallbuf */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001512 rdata->iov[0].iov_base = buf + server->total_read;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001513 rdata->iov[0].iov_len = len;
1514 length = cifs_readv_from_socket(server, rdata->iov, 1, len);
1515 if (length < 0)
1516 return length;
1517 server->total_read += length;
1518 }
1519
1520 /* set up first iov for signature check */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001521 rdata->iov[0].iov_base = buf;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001522 rdata->iov[0].iov_len = server->total_read;
1523 cFYI(1, "0: iov_base=%p iov_len=%zu",
1524 rdata->iov[0].iov_base, rdata->iov[0].iov_len);
1525
1526 /* how much data is in the response? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001527 data_len = server->ops->read_data_length(buf);
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001528 if (data_offset + data_len > buflen) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001529 /* data_len is corrupt -- discard frame */
1530 rdata->result = -EIO;
1531 return cifs_readv_discard(server, mid);
1532 }
1533
1534 /* marshal up the page array */
Jeff Layton3cf003c2012-07-11 09:09:36 -04001535 cifs_kmap_lock();
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001536 len = rdata->marshal_iov(rdata, data_len);
Jeff Layton3cf003c2012-07-11 09:09:36 -04001537 cifs_kmap_unlock();
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001538 data_len -= len;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001539
1540 /* issue the read if we have any iovecs left to fill */
1541 if (rdata->nr_iov > 1) {
1542 length = cifs_readv_from_socket(server, &rdata->iov[1],
1543 rdata->nr_iov - 1, len);
1544 if (length < 0)
1545 return length;
1546 server->total_read += length;
1547 } else {
1548 length = 0;
1549 }
1550
1551 rdata->bytes = length;
1552
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001553 cFYI(1, "total_read=%u buflen=%u remaining=%u", server->total_read,
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001554 buflen, data_len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001555
1556 /* discard anything left over */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001557 if (server->total_read < buflen)
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001558 return cifs_readv_discard(server, mid);
1559
1560 dequeue_mid(mid, false);
1561 return length;
1562}
1563
1564static void
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001565cifs_readv_callback(struct mid_q_entry *mid)
1566{
1567 struct cifs_readdata *rdata = mid->callback_data;
1568 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1569 struct TCP_Server_Info *server = tcon->ses->server;
1570
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001571 cFYI(1, "%s: mid=%llu state=%d result=%d bytes=%u", __func__,
1572 mid->mid, mid->mid_state, rdata->result, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001573
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001574 switch (mid->mid_state) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001575 case MID_RESPONSE_RECEIVED:
1576 /* result already set, check signature */
1577 if (server->sec_mode &
1578 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
Steve French985e4ff02012-08-03 09:42:45 -05001579 int rc = 0;
1580
1581 rc = cifs_verify_signature(rdata->iov, rdata->nr_iov,
1582 server,
1583 mid->sequence_number + 1);
1584 if (rc)
1585 cERROR(1, "SMB signature verification returned "
1586 "error = %d", rc);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001587 }
1588 /* FIXME: should this be counted toward the initiating task? */
1589 task_io_account_read(rdata->bytes);
1590 cifs_stats_bytes_read(tcon, rdata->bytes);
1591 break;
1592 case MID_REQUEST_SUBMITTED:
1593 case MID_RETRY_NEEDED:
1594 rdata->result = -EAGAIN;
1595 break;
1596 default:
1597 rdata->result = -EIO;
1598 }
1599
Jeff Laytonda472fc2012-03-23 14:40:53 -04001600 queue_work(cifsiod_wq, &rdata->work);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001601 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04001602 add_credits(server, 1, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001603}
1604
1605/* cifs_async_readv - send an async write, and set up mid to handle result */
1606int
1607cifs_async_readv(struct cifs_readdata *rdata)
1608{
1609 int rc;
1610 READ_REQ *smb = NULL;
1611 int wct;
1612 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1613
1614 cFYI(1, "%s: offset=%llu bytes=%u", __func__,
1615 rdata->offset, rdata->bytes);
1616
1617 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1618 wct = 12;
1619 else {
1620 wct = 10; /* old style read */
1621 if ((rdata->offset >> 32) > 0) {
1622 /* can not handle this big offset for old */
1623 return -EIO;
1624 }
1625 }
1626
1627 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **)&smb);
1628 if (rc)
1629 return rc;
1630
1631 smb->hdr.Pid = cpu_to_le16((__u16)rdata->pid);
1632 smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16));
1633
1634 smb->AndXCommand = 0xFF; /* none */
1635 smb->Fid = rdata->cfile->netfid;
1636 smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF);
1637 if (wct == 12)
1638 smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32);
1639 smb->Remaining = 0;
1640 smb->MaxCount = cpu_to_le16(rdata->bytes & 0xFFFF);
1641 smb->MaxCountHigh = cpu_to_le32(rdata->bytes >> 16);
1642 if (wct == 12)
1643 smb->ByteCount = 0;
1644 else {
1645 /* old style read */
1646 struct smb_com_readx_req *smbr =
1647 (struct smb_com_readx_req *)smb;
1648 smbr->ByteCount = 0;
1649 }
1650
1651 /* 4 for RFC1001 length + 1 for BCC */
1652 rdata->iov[0].iov_base = smb;
1653 rdata->iov[0].iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
1654
Jeff Layton6993f742012-05-16 07:13:17 -04001655 kref_get(&rdata->refcount);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001656 rc = cifs_call_async(tcon->ses->server, rdata->iov, 1,
1657 cifs_readv_receive, cifs_readv_callback,
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04001658 rdata, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001659
1660 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001661 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Jeff Layton6993f742012-05-16 07:13:17 -04001662 else
1663 kref_put(&rdata->refcount, cifs_readdata_release);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001664
1665 cifs_small_buf_release(smb);
1666 return rc;
1667}
1668
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001670CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
1671 unsigned int *nbytes, char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672{
1673 int rc = -EACCES;
1674 READ_REQ *pSMB = NULL;
1675 READ_RSP *pSMBr = NULL;
1676 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001677 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001678 int resp_buf_type = 0;
1679 struct kvec iov[1];
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001680 __u32 pid = io_parms->pid;
1681 __u16 netfid = io_parms->netfid;
1682 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001683 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001684 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685
Joe Perchesb6b38f72010-04-21 03:50:45 +00001686 cFYI(1, "Reading %d bytes on fid %d", count, netfid);
Steve French790fe572007-07-07 19:25:05 +00001687 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001688 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001689 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001690 wct = 10; /* old style read */
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001691 if ((offset >> 32) > 0) {
Steve French4c3130e2008-12-09 00:28:16 +00001692 /* can not handle this big offset for old */
1693 return -EIO;
1694 }
1695 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696
1697 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001698 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699 if (rc)
1700 return rc;
1701
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001702 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1703 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1704
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705 /* tcon and ses pointer are checked in smb_init */
1706 if (tcon->ses->server == NULL)
1707 return -ECONNABORTED;
1708
Steve Frenchec637e32005-12-12 20:53:18 -08001709 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710 pSMB->Fid = netfid;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001711 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001712 if (wct == 12)
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001713 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001714
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715 pSMB->Remaining = 0;
1716 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1717 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001718 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001719 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1720 else {
1721 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001722 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001723 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001724 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001725 }
Steve Frenchec637e32005-12-12 20:53:18 -08001726
1727 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001728 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve Frencha761ac52007-10-18 21:45:27 +00001729 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Jeff Layton77499812011-01-11 07:24:23 -05001730 &resp_buf_type, CIFS_LOG_ERROR);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001731 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001732 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001734 cERROR(1, "Send error in read = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735 } else {
1736 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1737 data_length = data_length << 16;
1738 data_length += le16_to_cpu(pSMBr->DataLength);
1739 *nbytes = data_length;
1740
1741 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001742 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743 || (data_length > count)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001744 cFYI(1, "bad length %d for count %d",
1745 data_length, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746 rc = -EIO;
1747 *nbytes = 0;
1748 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001749 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001750 le16_to_cpu(pSMBr->DataOffset);
1751/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001752 cERROR(1, "Faulting on read rc = %d",rc);
Steve French50c2f752007-07-13 00:33:32 +00001753 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001754 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001755 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001756 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757 }
1758 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759
Steve French4b8f9302006-02-26 16:41:18 +00001760/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001761 if (*buf) {
1762 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001763 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001764 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001765 cifs_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001766 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001767 /* return buffer to caller to free */
1768 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001769 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001770 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001771 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001772 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001773 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001774
1775 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776 since file handle passed in no longer valid */
1777 return rc;
1778}
1779
Steve Frenchec637e32005-12-12 20:53:18 -08001780
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001782CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001783 unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001784 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785{
1786 int rc = -EACCES;
1787 WRITE_REQ *pSMB = NULL;
1788 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001789 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001790 __u32 bytes_sent;
1791 __u16 byte_count;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001792 __u32 pid = io_parms->pid;
1793 __u16 netfid = io_parms->netfid;
1794 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001795 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001796 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797
Steve Frencha24e2d72010-04-03 17:20:21 +00001798 *nbytes = 0;
1799
Joe Perchesb6b38f72010-04-21 03:50:45 +00001800 /* cFYI(1, "write at %lld %d bytes", offset, count);*/
Steve French790fe572007-07-07 19:25:05 +00001801 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001802 return -ECONNABORTED;
1803
Steve French790fe572007-07-07 19:25:05 +00001804 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001805 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001806 else {
Steve French1c955182005-08-30 20:58:07 -07001807 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001808 if ((offset >> 32) > 0) {
1809 /* can not handle big offset for old srv */
1810 return -EIO;
1811 }
1812 }
Steve French1c955182005-08-30 20:58:07 -07001813
1814 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815 (void **) &pSMBr);
1816 if (rc)
1817 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001818
1819 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
1826 pSMB->AndXCommand = 0xFF; /* none */
1827 pSMB->Fid = netfid;
1828 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001829 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001830 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001831
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832 pSMB->Reserved = 0xFFFFFFFF;
1833 pSMB->WriteMode = 0;
1834 pSMB->Remaining = 0;
1835
Steve French50c2f752007-07-13 00:33:32 +00001836 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837 can send more if LARGE_WRITE_X capability returned by the server and if
1838 our buffer is big enough or if we convert to iovecs on socket writes
1839 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001840 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1842 } else {
1843 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1844 & ~0xFF;
1845 }
1846
1847 if (bytes_sent > count)
1848 bytes_sent = count;
1849 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001850 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001851 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001852 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001853 else if (ubuf) {
1854 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855 cifs_buf_release(pSMB);
1856 return -EFAULT;
1857 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001858 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859 /* No buffer */
1860 cifs_buf_release(pSMB);
1861 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001862 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001863 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001864 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001865 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001866 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001867
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1869 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001870 inc_rfc1001_len(pSMB, byte_count);
Steve French1c955182005-08-30 20:58:07 -07001871
Steve French790fe572007-07-07 19:25:05 +00001872 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001873 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001874 else { /* old style write has byte count 4 bytes earlier
1875 so 4 bytes pad */
1876 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001877 (struct smb_com_writex_req *)pSMB;
1878 pSMBW->ByteCount = cpu_to_le16(byte_count);
1879 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001880
1881 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1882 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001883 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00001885 cFYI(1, "Send error in write = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886 } else {
1887 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1888 *nbytes = (*nbytes) << 16;
1889 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301890
1891 /*
1892 * Mask off high 16 bits when bytes written as returned by the
1893 * server is greater than bytes requested by the client. Some
1894 * OS/2 servers are known to set incorrect CountHigh values.
1895 */
1896 if (*nbytes > count)
1897 *nbytes &= 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898 }
1899
1900 cifs_buf_release(pSMB);
1901
Steve French50c2f752007-07-13 00:33:32 +00001902 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903 since file handle passed in no longer valid */
1904
1905 return rc;
1906}
1907
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001908void
1909cifs_writedata_release(struct kref *refcount)
1910{
1911 struct cifs_writedata *wdata = container_of(refcount,
1912 struct cifs_writedata, refcount);
1913
1914 if (wdata->cfile)
1915 cifsFileInfo_put(wdata->cfile);
1916
1917 kfree(wdata);
1918}
1919
1920/*
1921 * Write failed with a retryable error. Resend the write request. It's also
1922 * possible that the page was redirtied so re-clean the page.
1923 */
1924static void
1925cifs_writev_requeue(struct cifs_writedata *wdata)
1926{
1927 int i, rc;
1928 struct inode *inode = wdata->cfile->dentry->d_inode;
1929
1930 for (i = 0; i < wdata->nr_pages; i++) {
1931 lock_page(wdata->pages[i]);
1932 clear_page_dirty_for_io(wdata->pages[i]);
1933 }
1934
1935 do {
1936 rc = cifs_async_writev(wdata);
1937 } while (rc == -EAGAIN);
1938
1939 for (i = 0; i < wdata->nr_pages; i++) {
1940 if (rc != 0)
1941 SetPageError(wdata->pages[i]);
1942 unlock_page(wdata->pages[i]);
1943 }
1944
1945 mapping_set_error(inode->i_mapping, rc);
1946 kref_put(&wdata->refcount, cifs_writedata_release);
1947}
1948
Jeff Laytonc2e87642012-03-23 14:40:55 -04001949void
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001950cifs_writev_complete(struct work_struct *work)
1951{
1952 struct cifs_writedata *wdata = container_of(work,
1953 struct cifs_writedata, work);
1954 struct inode *inode = wdata->cfile->dentry->d_inode;
1955 int i = 0;
1956
1957 if (wdata->result == 0) {
Jeff Layton597b0272012-03-23 14:40:56 -04001958 spin_lock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001959 cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
Jeff Layton597b0272012-03-23 14:40:56 -04001960 spin_unlock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001961 cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
1962 wdata->bytes);
1963 } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
1964 return cifs_writev_requeue(wdata);
1965
1966 for (i = 0; i < wdata->nr_pages; i++) {
1967 struct page *page = wdata->pages[i];
1968 if (wdata->result == -EAGAIN)
1969 __set_page_dirty_nobuffers(page);
1970 else if (wdata->result < 0)
1971 SetPageError(page);
1972 end_page_writeback(page);
1973 page_cache_release(page);
1974 }
1975 if (wdata->result != -EAGAIN)
1976 mapping_set_error(inode->i_mapping, wdata->result);
1977 kref_put(&wdata->refcount, cifs_writedata_release);
1978}
1979
1980struct cifs_writedata *
Jeff Laytonc2e87642012-03-23 14:40:55 -04001981cifs_writedata_alloc(unsigned int nr_pages, work_func_t complete)
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001982{
1983 struct cifs_writedata *wdata;
1984
1985 /* this would overflow */
1986 if (nr_pages == 0) {
1987 cERROR(1, "%s: called with nr_pages == 0!", __func__);
1988 return NULL;
1989 }
1990
1991 /* writedata + number of page pointers */
1992 wdata = kzalloc(sizeof(*wdata) +
1993 sizeof(struct page *) * (nr_pages - 1), GFP_NOFS);
1994 if (wdata != NULL) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001995 kref_init(&wdata->refcount);
Jeff Laytonda82f7e2012-03-23 14:40:56 -04001996 INIT_LIST_HEAD(&wdata->list);
1997 init_completion(&wdata->done);
1998 INIT_WORK(&wdata->work, complete);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001999 }
2000 return wdata;
2001}
2002
2003/*
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04002004 * Check the mid_state and signature on received buffer (if any), and queue the
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002005 * workqueue completion task.
2006 */
2007static void
2008cifs_writev_callback(struct mid_q_entry *mid)
2009{
2010 struct cifs_writedata *wdata = mid->callback_data;
Steve French96daf2b2011-05-27 04:34:02 +00002011 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002012 unsigned int written;
2013 WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
2014
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04002015 switch (mid->mid_state) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002016 case MID_RESPONSE_RECEIVED:
2017 wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
2018 if (wdata->result != 0)
2019 break;
2020
2021 written = le16_to_cpu(smb->CountHigh);
2022 written <<= 16;
2023 written += le16_to_cpu(smb->Count);
2024 /*
2025 * Mask off high 16 bits when bytes written as returned
2026 * by the server is greater than bytes requested by the
2027 * client. OS/2 servers are known to set incorrect
2028 * CountHigh values.
2029 */
2030 if (written > wdata->bytes)
2031 written &= 0xFFFF;
2032
2033 if (written < wdata->bytes)
2034 wdata->result = -ENOSPC;
2035 else
2036 wdata->bytes = written;
2037 break;
2038 case MID_REQUEST_SUBMITTED:
2039 case MID_RETRY_NEEDED:
2040 wdata->result = -EAGAIN;
2041 break;
2042 default:
2043 wdata->result = -EIO;
2044 break;
2045 }
2046
Jeff Laytonda472fc2012-03-23 14:40:53 -04002047 queue_work(cifsiod_wq, &wdata->work);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002048 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002049 add_credits(tcon->ses->server, 1, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002050}
2051
2052/* cifs_async_writev - send an async write, and set up mid to handle result */
2053int
2054cifs_async_writev(struct cifs_writedata *wdata)
2055{
2056 int i, rc = -EACCES;
2057 WRITE_REQ *smb = NULL;
2058 int wct;
Steve French96daf2b2011-05-27 04:34:02 +00002059 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002060 struct kvec *iov = NULL;
2061
2062 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
2063 wct = 14;
2064 } else {
2065 wct = 12;
2066 if (wdata->offset >> 32 > 0) {
2067 /* can not handle big offset for old srv */
2068 return -EIO;
2069 }
2070 }
2071
2072 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
2073 if (rc)
2074 goto async_writev_out;
2075
2076 /* 1 iov per page + 1 for header */
2077 iov = kzalloc((wdata->nr_pages + 1) * sizeof(*iov), GFP_NOFS);
2078 if (iov == NULL) {
2079 rc = -ENOMEM;
2080 goto async_writev_out;
2081 }
2082
Jeff Laytonfe5f5d22012-03-23 14:40:55 -04002083 smb->hdr.Pid = cpu_to_le16((__u16)wdata->pid);
2084 smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16));
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002085
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002086 smb->AndXCommand = 0xFF; /* none */
2087 smb->Fid = wdata->cfile->netfid;
2088 smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
2089 if (wct == 14)
2090 smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
2091 smb->Reserved = 0xFFFFFFFF;
2092 smb->WriteMode = 0;
2093 smb->Remaining = 0;
2094
2095 smb->DataOffset =
2096 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
2097
2098 /* 4 for RFC1001 length + 1 for BCC */
2099 iov[0].iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4 + 1;
2100 iov[0].iov_base = smb;
2101
Jeff Laytone9492872012-03-23 14:40:56 -04002102 /*
2103 * This function should marshal up the page array into the kvec
2104 * array, reserving [0] for the header. It should kmap the pages
2105 * and set the iov_len properly for each one. It may also set
2106 * wdata->bytes too.
2107 */
Jeff Layton3cf003c2012-07-11 09:09:36 -04002108 cifs_kmap_lock();
Jeff Laytone9492872012-03-23 14:40:56 -04002109 wdata->marshal_iov(iov, wdata);
Jeff Layton3cf003c2012-07-11 09:09:36 -04002110 cifs_kmap_unlock();
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002111
2112 cFYI(1, "async write at %llu %u bytes", wdata->offset, wdata->bytes);
2113
2114 smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
2115 smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16);
2116
2117 if (wct == 14) {
2118 inc_rfc1001_len(&smb->hdr, wdata->bytes + 1);
2119 put_bcc(wdata->bytes + 1, &smb->hdr);
2120 } else {
2121 /* wct == 12 */
2122 struct smb_com_writex_req *smbw =
2123 (struct smb_com_writex_req *)smb;
2124 inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
2125 put_bcc(wdata->bytes + 5, &smbw->hdr);
2126 iov[0].iov_len += 4; /* pad bigger by four bytes */
2127 }
2128
2129 kref_get(&wdata->refcount);
2130 rc = cifs_call_async(tcon->ses->server, iov, wdata->nr_pages + 1,
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002131 NULL, cifs_writev_callback, wdata, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002132
2133 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002134 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002135 else
2136 kref_put(&wdata->refcount, cifs_writedata_release);
2137
2138 /* send is done, unmap pages */
2139 for (i = 0; i < wdata->nr_pages; i++)
2140 kunmap(wdata->pages[i]);
2141
2142async_writev_out:
2143 cifs_small_buf_release(smb);
2144 kfree(iov);
2145 return rc;
2146}
2147
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002148int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002149CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002150 unsigned int *nbytes, struct kvec *iov, int n_vec,
2151 const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002152{
2153 int rc = -EACCES;
2154 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08002155 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002156 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08002157 int resp_buf_type = 0;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002158 __u32 pid = io_parms->pid;
2159 __u16 netfid = io_parms->netfid;
2160 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00002161 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002162 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002163
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04002164 *nbytes = 0;
2165
Joe Perchesb6b38f72010-04-21 03:50:45 +00002166 cFYI(1, "write2 at %lld %d bytes", (long long)offset, count);
Steve Frenchff7feac2005-11-15 16:45:16 -08002167
Steve French4c3130e2008-12-09 00:28:16 +00002168 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07002169 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00002170 } else {
Steve French8cc64c62005-10-03 13:49:43 -07002171 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00002172 if ((offset >> 32) > 0) {
2173 /* can not handle big offset for old srv */
2174 return -EIO;
2175 }
2176 }
Steve French8cc64c62005-10-03 13:49:43 -07002177 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002178 if (rc)
2179 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002180
2181 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
2182 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
2183
Linus Torvalds1da177e2005-04-16 15:20:36 -07002184 /* tcon and ses pointer are checked in smb_init */
2185 if (tcon->ses->server == NULL)
2186 return -ECONNABORTED;
2187
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002188 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002189 pSMB->Fid = netfid;
2190 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00002191 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002192 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002193 pSMB->Reserved = 0xFFFFFFFF;
2194 pSMB->WriteMode = 0;
2195 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002196
Linus Torvalds1da177e2005-04-16 15:20:36 -07002197 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00002198 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002199
Steve French3e844692005-10-03 13:37:24 -07002200 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
2201 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002202 /* header + 1 byte pad */
2203 smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
Steve French790fe572007-07-07 19:25:05 +00002204 if (wct == 14)
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002205 inc_rfc1001_len(pSMB, count + 1);
Steve French8cc64c62005-10-03 13:49:43 -07002206 else /* wct == 12 */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002207 inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
Steve French790fe572007-07-07 19:25:05 +00002208 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002209 pSMB->ByteCount = cpu_to_le16(count + 1);
2210 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00002211 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07002212 (struct smb_com_writex_req *)pSMB;
2213 pSMBW->ByteCount = cpu_to_le16(count + 5);
2214 }
Steve French3e844692005-10-03 13:37:24 -07002215 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00002216 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08002217 iov[0].iov_len = smb_hdr_len + 4;
2218 else /* wct == 12 pad bigger by four bytes */
2219 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00002220
Steve French3e844692005-10-03 13:37:24 -07002221
Steve Frenchec637e32005-12-12 20:53:18 -08002222 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French133672e2007-11-13 22:41:37 +00002223 long_op);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002224 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002225 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002226 cFYI(1, "Send error Write2 = %d", rc);
Steve French790fe572007-07-07 19:25:05 +00002227 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08002228 /* presumably this can not happen, but best to be safe */
2229 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002230 } else {
Steve Frenchad7a2922008-02-07 23:25:02 +00002231 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002232 *nbytes = le16_to_cpu(pSMBr->CountHigh);
2233 *nbytes = (*nbytes) << 16;
2234 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05302235
2236 /*
2237 * Mask off high 16 bits when bytes written as returned by the
2238 * server is greater than bytes requested by the client. OS/2
2239 * servers are known to set incorrect CountHigh values.
2240 */
2241 if (*nbytes > count)
2242 *nbytes &= 0xFFFF;
Steve French50c2f752007-07-13 00:33:32 +00002243 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002244
Steve French4b8f9302006-02-26 16:41:18 +00002245/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00002246 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002247 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00002248 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002249 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002250
Steve French50c2f752007-07-13 00:33:32 +00002251 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002252 since file handle passed in no longer valid */
2253
2254 return rc;
2255}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002256
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002257int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon,
2258 const __u16 netfid, const __u8 lock_type, const __u32 num_unlock,
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002259 const __u32 num_lock, LOCKING_ANDX_RANGE *buf)
2260{
2261 int rc = 0;
2262 LOCK_REQ *pSMB = NULL;
2263 struct kvec iov[2];
2264 int resp_buf_type;
2265 __u16 count;
2266
2267 cFYI(1, "cifs_lockv num lock %d num unlock %d", num_lock, num_unlock);
2268
2269 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2270 if (rc)
2271 return rc;
2272
2273 pSMB->Timeout = 0;
2274 pSMB->NumberOfLocks = cpu_to_le16(num_lock);
2275 pSMB->NumberOfUnlocks = cpu_to_le16(num_unlock);
2276 pSMB->LockType = lock_type;
2277 pSMB->AndXCommand = 0xFF; /* none */
2278 pSMB->Fid = netfid; /* netfid stays le */
2279
2280 count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2281 inc_rfc1001_len(pSMB, count);
2282 pSMB->ByteCount = cpu_to_le16(count);
2283
2284 iov[0].iov_base = (char *)pSMB;
2285 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 -
2286 (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2287 iov[1].iov_base = (char *)buf;
2288 iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2289
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002290 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002291 rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP);
2292 if (rc)
2293 cFYI(1, "Send error in cifs_lockv = %d", rc);
2294
2295 return rc;
2296}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002297
Linus Torvalds1da177e2005-04-16 15:20:36 -07002298int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002299CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002300 const __u16 smb_file_id, const __u32 netpid, const __u64 len,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002301 const __u64 offset, const __u32 numUnlock,
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002302 const __u32 numLock, const __u8 lockType,
2303 const bool waitFlag, const __u8 oplock_level)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002304{
2305 int rc = 0;
2306 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002307/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002308 int bytes_returned;
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002309 int flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310 __u16 count;
2311
Joe Perchesb6b38f72010-04-21 03:50:45 +00002312 cFYI(1, "CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock);
Steve French46810cb2005-04-28 22:41:09 -07002313 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2314
Linus Torvalds1da177e2005-04-16 15:20:36 -07002315 if (rc)
2316 return rc;
2317
Steve French790fe572007-07-07 19:25:05 +00002318 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002319 /* no response expected */
2320 flags = CIFS_ASYNC_OP | CIFS_OBREAK_OP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002321 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00002322 } else if (waitFlag) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002323 flags = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002324 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
2325 } else {
2326 pSMB->Timeout = 0;
2327 }
2328
2329 pSMB->NumberOfLocks = cpu_to_le16(numLock);
2330 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
2331 pSMB->LockType = lockType;
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002332 pSMB->OplockLevel = oplock_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002333 pSMB->AndXCommand = 0xFF; /* none */
2334 pSMB->Fid = smb_file_id; /* netfid stays le */
2335
Steve French790fe572007-07-07 19:25:05 +00002336 if ((numLock != 0) || (numUnlock != 0)) {
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002337 pSMB->Locks[0].Pid = cpu_to_le16(netpid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002338 /* BB where to store pid high? */
2339 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
2340 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
2341 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
2342 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
2343 count = sizeof(LOCKING_ANDX_RANGE);
2344 } else {
2345 /* oplock break */
2346 count = 0;
2347 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002348 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002349 pSMB->ByteCount = cpu_to_le16(count);
2350
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002351 if (waitFlag) {
2352 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002353 (struct smb_hdr *) pSMB, &bytes_returned);
Steve French133672e2007-11-13 22:41:37 +00002354 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002355 } else {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002356 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, flags);
Steve French133672e2007-11-13 22:41:37 +00002357 /* SMB buffer freed by function above */
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002358 }
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002359 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002360 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002361 cFYI(1, "Send error in Lock = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002362
Steve French50c2f752007-07-13 00:33:32 +00002363 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002364 since file handle passed in no longer valid */
2365 return rc;
2366}
2367
2368int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002369CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002370 const __u16 smb_file_id, const __u32 netpid,
2371 const loff_t start_offset, const __u64 len,
2372 struct file_lock *pLockData, const __u16 lock_type,
2373 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00002374{
2375 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2376 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00002377 struct cifs_posix_lock *parm_data;
2378 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00002379 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00002380 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00002381 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00002382 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00002383 struct kvec iov[1];
Steve French08547b02006-02-28 22:39:25 +00002384
Joe Perchesb6b38f72010-04-21 03:50:45 +00002385 cFYI(1, "Posix Lock");
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002386
Steve French08547b02006-02-28 22:39:25 +00002387 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
2388
2389 if (rc)
2390 return rc;
2391
2392 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
2393
Steve French50c2f752007-07-13 00:33:32 +00002394 params = 6;
Steve French08547b02006-02-28 22:39:25 +00002395 pSMB->MaxSetupCount = 0;
2396 pSMB->Reserved = 0;
2397 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00002398 pSMB->Reserved2 = 0;
2399 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2400 offset = param_offset + params;
2401
Steve French08547b02006-02-28 22:39:25 +00002402 count = sizeof(struct cifs_posix_lock);
2403 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002404 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00002405 pSMB->SetupCount = 1;
2406 pSMB->Reserved3 = 0;
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002407 if (pLockData)
Steve French08547b02006-02-28 22:39:25 +00002408 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2409 else
2410 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2411 byte_count = 3 /* pad */ + params + count;
2412 pSMB->DataCount = cpu_to_le16(count);
2413 pSMB->ParameterCount = cpu_to_le16(params);
2414 pSMB->TotalDataCount = pSMB->DataCount;
2415 pSMB->TotalParameterCount = pSMB->ParameterCount;
2416 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00002417 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00002418 (((char *) &pSMB->hdr.Protocol) + offset);
2419
2420 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00002421 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00002422 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00002423 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00002424 pSMB->Timeout = cpu_to_le32(-1);
2425 } else
2426 pSMB->Timeout = 0;
2427
Pavel Shilovsky4f6bcec2011-10-22 15:33:30 +04002428 parm_data->pid = cpu_to_le32(netpid);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002429 parm_data->start = cpu_to_le64(start_offset);
Steve Frenchcec6815a2006-05-30 18:07:17 +00002430 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00002431
2432 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00002433 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00002434 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
2435 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002436 inc_rfc1001_len(pSMB, byte_count);
Steve French08547b02006-02-28 22:39:25 +00002437 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002438 if (waitFlag) {
2439 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2440 (struct smb_hdr *) pSMBr, &bytes_returned);
2441 } else {
Steve French133672e2007-11-13 22:41:37 +00002442 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002443 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French133672e2007-11-13 22:41:37 +00002444 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
2445 &resp_buf_type, timeout);
2446 pSMB = NULL; /* request buf already freed by SendReceive2. Do
2447 not try to free it twice below on exit */
2448 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002449 }
2450
Steve French08547b02006-02-28 22:39:25 +00002451 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002452 cFYI(1, "Send error in Posix Lock = %d", rc);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002453 } else if (pLockData) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002454 /* lock structure can be returned on get */
2455 __u16 data_offset;
2456 __u16 data_count;
2457 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00002458
Jeff Layton820a8032011-05-04 08:05:26 -04002459 if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002460 rc = -EIO; /* bad smb */
2461 goto plk_err_exit;
2462 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002463 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2464 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00002465 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002466 rc = -EIO;
2467 goto plk_err_exit;
2468 }
2469 parm_data = (struct cifs_posix_lock *)
2470 ((char *)&pSMBr->hdr.Protocol + data_offset);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002471 if (parm_data->lock_type == __constant_cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002472 pLockData->fl_type = F_UNLCK;
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002473 else {
2474 if (parm_data->lock_type ==
2475 __constant_cpu_to_le16(CIFS_RDLCK))
2476 pLockData->fl_type = F_RDLCK;
2477 else if (parm_data->lock_type ==
2478 __constant_cpu_to_le16(CIFS_WRLCK))
2479 pLockData->fl_type = F_WRLCK;
2480
Steve French5443d132011-03-13 05:08:25 +00002481 pLockData->fl_start = le64_to_cpu(parm_data->start);
2482 pLockData->fl_end = pLockData->fl_start +
2483 le64_to_cpu(parm_data->length) - 1;
2484 pLockData->fl_pid = le32_to_cpu(parm_data->pid);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002485 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002486 }
Steve French50c2f752007-07-13 00:33:32 +00002487
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002488plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00002489 if (pSMB)
2490 cifs_small_buf_release(pSMB);
2491
Steve French133672e2007-11-13 22:41:37 +00002492 if (resp_buf_type == CIFS_SMALL_BUFFER)
2493 cifs_small_buf_release(iov[0].iov_base);
2494 else if (resp_buf_type == CIFS_LARGE_BUFFER)
2495 cifs_buf_release(iov[0].iov_base);
2496
Steve French08547b02006-02-28 22:39:25 +00002497 /* Note: On -EAGAIN error only caller can retry on handle based calls
2498 since file handle passed in no longer valid */
2499
2500 return rc;
2501}
2502
2503
2504int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002505CIFSSMBClose(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002506{
2507 int rc = 0;
2508 CLOSE_REQ *pSMB = NULL;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002509 cFYI(1, "In CIFSSMBClose");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002510
2511/* do not retry on dead session on close */
2512 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00002513 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002514 return 0;
2515 if (rc)
2516 return rc;
2517
Linus Torvalds1da177e2005-04-16 15:20:36 -07002518 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00002519 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002520 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002521 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002522 cifs_stats_inc(&tcon->stats.cifs_stats.num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002523 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00002524 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002525 /* EINTR is expected when user ctl-c to kill app */
Joe Perchesb6b38f72010-04-21 03:50:45 +00002526 cERROR(1, "Send error in Close = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002527 }
2528 }
2529
Linus Torvalds1da177e2005-04-16 15:20:36 -07002530 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00002531 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002532 rc = 0;
2533
2534 return rc;
2535}
2536
2537int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002538CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Steve Frenchb298f222009-02-21 21:17:43 +00002539{
2540 int rc = 0;
2541 FLUSH_REQ *pSMB = NULL;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002542 cFYI(1, "In CIFSSMBFlush");
Steve Frenchb298f222009-02-21 21:17:43 +00002543
2544 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
2545 if (rc)
2546 return rc;
2547
2548 pSMB->FileID = (__u16) smb_file_id;
2549 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002550 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002551 cifs_stats_inc(&tcon->stats.cifs_stats.num_flushes);
Steve Frenchb298f222009-02-21 21:17:43 +00002552 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002553 cERROR(1, "Send error in Flush = %d", rc);
Steve Frenchb298f222009-02-21 21:17:43 +00002554
2555 return rc;
2556}
2557
2558int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002559CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002560 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002561 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002562{
2563 int rc = 0;
2564 RENAME_REQ *pSMB = NULL;
2565 RENAME_RSP *pSMBr = NULL;
2566 int bytes_returned;
2567 int name_len, name_len2;
2568 __u16 count;
2569
Joe Perchesb6b38f72010-04-21 03:50:45 +00002570 cFYI(1, "In CIFSSMBRename");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002571renameRetry:
2572 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
2573 (void **) &pSMBr);
2574 if (rc)
2575 return rc;
2576
2577 pSMB->BufferFormat = 0x04;
2578 pSMB->SearchAttributes =
2579 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2580 ATTR_DIRECTORY);
2581
2582 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2583 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06002584 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, fromName,
2585 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002586 name_len++; /* trailing null */
2587 name_len *= 2;
2588 pSMB->OldFileName[name_len] = 0x04; /* pad */
2589 /* protocol requires ASCII signature byte on Unicode string */
2590 pSMB->OldFileName[name_len + 1] = 0x00;
2591 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002592 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2593 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002594 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2595 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002596 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002597 name_len = strnlen(fromName, PATH_MAX);
2598 name_len++; /* trailing null */
2599 strncpy(pSMB->OldFileName, fromName, name_len);
2600 name_len2 = strnlen(toName, PATH_MAX);
2601 name_len2++; /* trailing null */
2602 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2603 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2604 name_len2++; /* trailing null */
2605 name_len2++; /* signature byte */
2606 }
2607
2608 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002609 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002610 pSMB->ByteCount = cpu_to_le16(count);
2611
2612 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2613 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002614 cifs_stats_inc(&tcon->stats.cifs_stats.num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002615 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002616 cFYI(1, "Send error in rename = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002617
Linus Torvalds1da177e2005-04-16 15:20:36 -07002618 cifs_buf_release(pSMB);
2619
2620 if (rc == -EAGAIN)
2621 goto renameRetry;
2622
2623 return rc;
2624}
2625
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002626int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002627 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002628 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002629{
2630 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2631 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002632 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002633 char *data_offset;
2634 char dummy_string[30];
2635 int rc = 0;
2636 int bytes_returned = 0;
2637 int len_of_str;
2638 __u16 params, param_offset, offset, count, byte_count;
2639
Joe Perchesb6b38f72010-04-21 03:50:45 +00002640 cFYI(1, "Rename to File by handle");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002641 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2642 (void **) &pSMBr);
2643 if (rc)
2644 return rc;
2645
2646 params = 6;
2647 pSMB->MaxSetupCount = 0;
2648 pSMB->Reserved = 0;
2649 pSMB->Flags = 0;
2650 pSMB->Timeout = 0;
2651 pSMB->Reserved2 = 0;
2652 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2653 offset = param_offset + params;
2654
2655 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2656 rename_info = (struct set_file_rename *) data_offset;
2657 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002658 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002659 pSMB->SetupCount = 1;
2660 pSMB->Reserved3 = 0;
2661 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2662 byte_count = 3 /* pad */ + params;
2663 pSMB->ParameterCount = cpu_to_le16(params);
2664 pSMB->TotalParameterCount = pSMB->ParameterCount;
2665 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2666 pSMB->DataOffset = cpu_to_le16(offset);
2667 /* construct random name ".cifs_tmp<inodenum><mid>" */
2668 rename_info->overwrite = cpu_to_le32(1);
2669 rename_info->root_fid = 0;
2670 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002671 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002672 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
Steve Frenchacbbb762012-01-18 22:32:33 -06002673 len_of_str =
2674 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002675 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002676 } else {
Steve Frenchacbbb762012-01-18 22:32:33 -06002677 len_of_str =
2678 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002679 target_name, PATH_MAX, nls_codepage,
2680 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002681 }
2682 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002683 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002684 byte_count += count;
2685 pSMB->DataCount = cpu_to_le16(count);
2686 pSMB->TotalDataCount = pSMB->DataCount;
2687 pSMB->Fid = netfid;
2688 pSMB->InformationLevel =
2689 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2690 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002691 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002692 pSMB->ByteCount = cpu_to_le16(byte_count);
2693 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002694 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002695 cifs_stats_inc(&pTcon->stats.cifs_stats.num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002696 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002697 cFYI(1, "Send error in Rename (by file handle) = %d", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07002698
Linus Torvalds1da177e2005-04-16 15:20:36 -07002699 cifs_buf_release(pSMB);
2700
2701 /* Note: On -EAGAIN error only caller can retry on handle based calls
2702 since file handle passed in no longer valid */
2703
2704 return rc;
2705}
2706
2707int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002708CIFSSMBCopy(const unsigned int xid, struct cifs_tcon *tcon,
2709 const char *fromName, const __u16 target_tid, const char *toName,
2710 const int flags, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002711{
2712 int rc = 0;
2713 COPY_REQ *pSMB = NULL;
2714 COPY_RSP *pSMBr = NULL;
2715 int bytes_returned;
2716 int name_len, name_len2;
2717 __u16 count;
2718
Joe Perchesb6b38f72010-04-21 03:50:45 +00002719 cFYI(1, "In CIFSSMBCopy");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002720copyRetry:
2721 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2722 (void **) &pSMBr);
2723 if (rc)
2724 return rc;
2725
2726 pSMB->BufferFormat = 0x04;
2727 pSMB->Tid2 = target_tid;
2728
2729 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2730
2731 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002732 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2733 fromName, PATH_MAX, nls_codepage,
2734 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735 name_len++; /* trailing null */
2736 name_len *= 2;
2737 pSMB->OldFileName[name_len] = 0x04; /* pad */
2738 /* protocol requires ASCII signature byte on Unicode string */
2739 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002740 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002741 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2742 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002743 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2744 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002745 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002746 name_len = strnlen(fromName, PATH_MAX);
2747 name_len++; /* trailing null */
2748 strncpy(pSMB->OldFileName, fromName, name_len);
2749 name_len2 = strnlen(toName, PATH_MAX);
2750 name_len2++; /* trailing null */
2751 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2752 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2753 name_len2++; /* trailing null */
2754 name_len2++; /* signature byte */
2755 }
2756
2757 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002758 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002759 pSMB->ByteCount = cpu_to_le16(count);
2760
2761 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2762 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2763 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002764 cFYI(1, "Send error in copy = %d with %d files copied",
2765 rc, le16_to_cpu(pSMBr->CopyCount));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002766 }
Steve French0d817bc2008-05-22 02:02:03 +00002767 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002768
2769 if (rc == -EAGAIN)
2770 goto copyRetry;
2771
2772 return rc;
2773}
2774
2775int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002776CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002777 const char *fromName, const char *toName,
2778 const struct nls_table *nls_codepage)
2779{
2780 TRANSACTION2_SPI_REQ *pSMB = NULL;
2781 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2782 char *data_offset;
2783 int name_len;
2784 int name_len_target;
2785 int rc = 0;
2786 int bytes_returned = 0;
2787 __u16 params, param_offset, offset, byte_count;
2788
Joe Perchesb6b38f72010-04-21 03:50:45 +00002789 cFYI(1, "In Symlink Unix style");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002790createSymLinkRetry:
2791 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2792 (void **) &pSMBr);
2793 if (rc)
2794 return rc;
2795
2796 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2797 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06002798 cifs_strtoUTF16((__le16 *) pSMB->FileName, fromName,
2799 /* find define for this maxpathcomponent */
2800 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002801 name_len++; /* trailing null */
2802 name_len *= 2;
2803
Steve French50c2f752007-07-13 00:33:32 +00002804 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002805 name_len = strnlen(fromName, PATH_MAX);
2806 name_len++; /* trailing null */
2807 strncpy(pSMB->FileName, fromName, name_len);
2808 }
2809 params = 6 + name_len;
2810 pSMB->MaxSetupCount = 0;
2811 pSMB->Reserved = 0;
2812 pSMB->Flags = 0;
2813 pSMB->Timeout = 0;
2814 pSMB->Reserved2 = 0;
2815 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002816 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002817 offset = param_offset + params;
2818
2819 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2820 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2821 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06002822 cifs_strtoUTF16((__le16 *) data_offset, toName, PATH_MAX
2823 /* find define for this maxpathcomponent */
2824 , nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002825 name_len_target++; /* trailing null */
2826 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002827 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002828 name_len_target = strnlen(toName, PATH_MAX);
2829 name_len_target++; /* trailing null */
2830 strncpy(data_offset, toName, name_len_target);
2831 }
2832
2833 pSMB->MaxParameterCount = cpu_to_le16(2);
2834 /* BB find exact max on data count below from sess */
2835 pSMB->MaxDataCount = cpu_to_le16(1000);
2836 pSMB->SetupCount = 1;
2837 pSMB->Reserved3 = 0;
2838 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2839 byte_count = 3 /* pad */ + params + name_len_target;
2840 pSMB->DataCount = cpu_to_le16(name_len_target);
2841 pSMB->ParameterCount = cpu_to_le16(params);
2842 pSMB->TotalDataCount = pSMB->DataCount;
2843 pSMB->TotalParameterCount = pSMB->ParameterCount;
2844 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2845 pSMB->DataOffset = cpu_to_le16(offset);
2846 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2847 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002848 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002849 pSMB->ByteCount = cpu_to_le16(byte_count);
2850 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2851 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002852 cifs_stats_inc(&tcon->stats.cifs_stats.num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002853 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002854 cFYI(1, "Send error in SetPathInfo create symlink = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002855
Steve French0d817bc2008-05-22 02:02:03 +00002856 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002857
2858 if (rc == -EAGAIN)
2859 goto createSymLinkRetry;
2860
2861 return rc;
2862}
2863
2864int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002865CIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002866 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002867 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002868{
2869 TRANSACTION2_SPI_REQ *pSMB = NULL;
2870 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2871 char *data_offset;
2872 int name_len;
2873 int name_len_target;
2874 int rc = 0;
2875 int bytes_returned = 0;
2876 __u16 params, param_offset, offset, byte_count;
2877
Joe Perchesb6b38f72010-04-21 03:50:45 +00002878 cFYI(1, "In Create Hard link Unix style");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002879createHardLinkRetry:
2880 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2881 (void **) &pSMBr);
2882 if (rc)
2883 return rc;
2884
2885 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002886 name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, toName,
2887 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002888 name_len++; /* trailing null */
2889 name_len *= 2;
2890
Steve French50c2f752007-07-13 00:33:32 +00002891 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002892 name_len = strnlen(toName, PATH_MAX);
2893 name_len++; /* trailing null */
2894 strncpy(pSMB->FileName, toName, name_len);
2895 }
2896 params = 6 + name_len;
2897 pSMB->MaxSetupCount = 0;
2898 pSMB->Reserved = 0;
2899 pSMB->Flags = 0;
2900 pSMB->Timeout = 0;
2901 pSMB->Reserved2 = 0;
2902 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002903 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002904 offset = param_offset + params;
2905
2906 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2907 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2908 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06002909 cifsConvertToUTF16((__le16 *) data_offset, fromName,
2910 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002911 name_len_target++; /* trailing null */
2912 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002913 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002914 name_len_target = strnlen(fromName, PATH_MAX);
2915 name_len_target++; /* trailing null */
2916 strncpy(data_offset, fromName, name_len_target);
2917 }
2918
2919 pSMB->MaxParameterCount = cpu_to_le16(2);
2920 /* BB find exact max on data count below from sess*/
2921 pSMB->MaxDataCount = cpu_to_le16(1000);
2922 pSMB->SetupCount = 1;
2923 pSMB->Reserved3 = 0;
2924 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2925 byte_count = 3 /* pad */ + params + name_len_target;
2926 pSMB->ParameterCount = cpu_to_le16(params);
2927 pSMB->TotalParameterCount = pSMB->ParameterCount;
2928 pSMB->DataCount = cpu_to_le16(name_len_target);
2929 pSMB->TotalDataCount = pSMB->DataCount;
2930 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2931 pSMB->DataOffset = cpu_to_le16(offset);
2932 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2933 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002934 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002935 pSMB->ByteCount = cpu_to_le16(byte_count);
2936 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2937 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002938 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002939 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002940 cFYI(1, "Send error in SetPathInfo (hard link) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002941
2942 cifs_buf_release(pSMB);
2943 if (rc == -EAGAIN)
2944 goto createHardLinkRetry;
2945
2946 return rc;
2947}
2948
2949int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002950CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002951 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002952 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002953{
2954 int rc = 0;
2955 NT_RENAME_REQ *pSMB = NULL;
2956 RENAME_RSP *pSMBr = NULL;
2957 int bytes_returned;
2958 int name_len, name_len2;
2959 __u16 count;
2960
Joe Perchesb6b38f72010-04-21 03:50:45 +00002961 cFYI(1, "In CIFSCreateHardLink");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002962winCreateHardLinkRetry:
2963
2964 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2965 (void **) &pSMBr);
2966 if (rc)
2967 return rc;
2968
2969 pSMB->SearchAttributes =
2970 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2971 ATTR_DIRECTORY);
2972 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2973 pSMB->ClusterCount = 0;
2974
2975 pSMB->BufferFormat = 0x04;
2976
2977 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2978 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06002979 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, fromName,
2980 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002981 name_len++; /* trailing null */
2982 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05002983
2984 /* protocol specifies ASCII buffer format (0x04) for unicode */
2985 pSMB->OldFileName[name_len] = 0x04;
2986 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002987 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002988 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2989 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002990 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2991 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002992 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002993 name_len = strnlen(fromName, PATH_MAX);
2994 name_len++; /* trailing null */
2995 strncpy(pSMB->OldFileName, fromName, name_len);
2996 name_len2 = strnlen(toName, PATH_MAX);
2997 name_len2++; /* trailing null */
2998 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2999 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
3000 name_len2++; /* trailing null */
3001 name_len2++; /* signature byte */
3002 }
3003
3004 count = 1 /* string type byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003005 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003006 pSMB->ByteCount = cpu_to_le16(count);
3007
3008 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3009 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003010 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00003011 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003012 cFYI(1, "Send error in hard link (NT rename) = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00003013
Linus Torvalds1da177e2005-04-16 15:20:36 -07003014 cifs_buf_release(pSMB);
3015 if (rc == -EAGAIN)
3016 goto winCreateHardLinkRetry;
3017
3018 return rc;
3019}
3020
3021int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003022CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04003023 const unsigned char *searchName, char **symlinkinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003024 const struct nls_table *nls_codepage)
3025{
3026/* SMB_QUERY_FILE_UNIX_LINK */
3027 TRANSACTION2_QPI_REQ *pSMB = NULL;
3028 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3029 int rc = 0;
3030 int bytes_returned;
3031 int name_len;
3032 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04003033 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003034
Joe Perchesb6b38f72010-04-21 03:50:45 +00003035 cFYI(1, "In QPathSymLinkInfo (Unix) for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003036
3037querySymLinkRetry:
3038 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3039 (void **) &pSMBr);
3040 if (rc)
3041 return rc;
3042
3043 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3044 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003045 cifs_strtoUTF16((__le16 *) pSMB->FileName, searchName,
3046 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003047 name_len++; /* trailing null */
3048 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003049 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003050 name_len = strnlen(searchName, PATH_MAX);
3051 name_len++; /* trailing null */
3052 strncpy(pSMB->FileName, searchName, name_len);
3053 }
3054
3055 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3056 pSMB->TotalDataCount = 0;
3057 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04003058 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003059 pSMB->MaxSetupCount = 0;
3060 pSMB->Reserved = 0;
3061 pSMB->Flags = 0;
3062 pSMB->Timeout = 0;
3063 pSMB->Reserved2 = 0;
3064 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003065 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003066 pSMB->DataCount = 0;
3067 pSMB->DataOffset = 0;
3068 pSMB->SetupCount = 1;
3069 pSMB->Reserved3 = 0;
3070 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3071 byte_count = params + 1 /* pad */ ;
3072 pSMB->TotalParameterCount = cpu_to_le16(params);
3073 pSMB->ParameterCount = pSMB->TotalParameterCount;
3074 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
3075 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003076 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003077 pSMB->ByteCount = cpu_to_le16(byte_count);
3078
3079 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3080 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3081 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003082 cFYI(1, "Send error in QuerySymLinkInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003083 } else {
3084 /* decode response */
3085
3086 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003087 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003088 if (rc || get_bcc(&pSMBr->hdr) < 2)
Jeff Layton460b9692009-04-30 07:17:56 -04003089 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003090 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00003091 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04003092 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003093
Jeff Layton460b9692009-04-30 07:17:56 -04003094 data_start = ((char *) &pSMBr->hdr.Protocol) +
3095 le16_to_cpu(pSMBr->t2.DataOffset);
3096
Steve French0e0d2cf2009-05-01 05:27:32 +00003097 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3098 is_unicode = true;
3099 else
3100 is_unicode = false;
3101
Steve French737b7582005-04-28 22:41:06 -07003102 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchacbbb762012-01-18 22:32:33 -06003103 *symlinkinfo = cifs_strndup_from_utf16(data_start,
3104 count, is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04003105 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04003106 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003107 }
3108 }
3109 cifs_buf_release(pSMB);
3110 if (rc == -EAGAIN)
3111 goto querySymLinkRetry;
3112 return rc;
3113}
3114
Steve Frenchc52a9552011-02-24 06:16:22 +00003115#ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL
3116/*
3117 * Recent Windows versions now create symlinks more frequently
3118 * and they use the "reparse point" mechanism below. We can of course
3119 * do symlinks nicely to Samba and other servers which support the
3120 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
3121 * "MF" symlinks optionally, but for recent Windows we really need to
3122 * reenable the code below and fix the cifs_symlink callers to handle this.
3123 * In the interim this code has been moved to its own config option so
3124 * it is not compiled in by default until callers fixed up and more tested.
3125 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003126int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003127CIFSSMBQueryReparseLinkInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003128 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00003129 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003130 const struct nls_table *nls_codepage)
3131{
3132 int rc = 0;
3133 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00003134 struct smb_com_transaction_ioctl_req *pSMB;
3135 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003136
Joe Perchesb6b38f72010-04-21 03:50:45 +00003137 cFYI(1, "In Windows reparse style QueryLink for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003138 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3139 (void **) &pSMBr);
3140 if (rc)
3141 return rc;
3142
3143 pSMB->TotalParameterCount = 0 ;
3144 pSMB->TotalDataCount = 0;
3145 pSMB->MaxParameterCount = cpu_to_le32(2);
3146 /* BB find exact data count max from sess structure BB */
Jeff Laytonc974bef2011-10-11 06:41:32 -04003147 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003148 pSMB->MaxSetupCount = 4;
3149 pSMB->Reserved = 0;
3150 pSMB->ParameterOffset = 0;
3151 pSMB->DataCount = 0;
3152 pSMB->DataOffset = 0;
3153 pSMB->SetupCount = 4;
3154 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
3155 pSMB->ParameterCount = pSMB->TotalParameterCount;
3156 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
3157 pSMB->IsFsctl = 1; /* FSCTL */
3158 pSMB->IsRootFlag = 0;
3159 pSMB->Fid = fid; /* file handle always le */
3160 pSMB->ByteCount = 0;
3161
3162 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3163 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3164 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003165 cFYI(1, "Send error in QueryReparseLinkInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003166 } else { /* decode response */
3167 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
3168 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
Jeff Layton820a8032011-05-04 08:05:26 -04003169 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
3170 /* BB also check enough total bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003171 rc = -EIO; /* bad smb */
Steve Frenchafe48c32009-05-02 05:25:46 +00003172 goto qreparse_out;
3173 }
3174 if (data_count && (data_count < 2048)) {
3175 char *end_of_smb = 2 /* sizeof byte count */ +
Jeff Layton820a8032011-05-04 08:05:26 -04003176 get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003177
Steve Frenchafe48c32009-05-02 05:25:46 +00003178 struct reparse_data *reparse_buf =
Steve French50c2f752007-07-13 00:33:32 +00003179 (struct reparse_data *)
3180 ((char *)&pSMBr->hdr.Protocol
3181 + data_offset);
Steve Frenchafe48c32009-05-02 05:25:46 +00003182 if ((char *)reparse_buf >= end_of_smb) {
3183 rc = -EIO;
3184 goto qreparse_out;
3185 }
3186 if ((reparse_buf->LinkNamesBuf +
3187 reparse_buf->TargetNameOffset +
3188 reparse_buf->TargetNameLen) > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003189 cFYI(1, "reparse buf beyond SMB");
Steve Frenchafe48c32009-05-02 05:25:46 +00003190 rc = -EIO;
3191 goto qreparse_out;
3192 }
Steve French50c2f752007-07-13 00:33:32 +00003193
Steve Frenchafe48c32009-05-02 05:25:46 +00003194 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3195 cifs_from_ucs2(symlinkinfo, (__le16 *)
Steve French50c2f752007-07-13 00:33:32 +00003196 (reparse_buf->LinkNamesBuf +
3197 reparse_buf->TargetNameOffset),
Steve Frenchafe48c32009-05-02 05:25:46 +00003198 buflen,
3199 reparse_buf->TargetNameLen,
3200 nls_codepage, 0);
3201 } else { /* ASCII names */
3202 strncpy(symlinkinfo,
3203 reparse_buf->LinkNamesBuf +
3204 reparse_buf->TargetNameOffset,
3205 min_t(const int, buflen,
3206 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003207 }
Steve Frenchafe48c32009-05-02 05:25:46 +00003208 } else {
3209 rc = -EIO;
Joe Perchesb6b38f72010-04-21 03:50:45 +00003210 cFYI(1, "Invalid return data count on "
3211 "get reparse info ioctl");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003212 }
Steve Frenchafe48c32009-05-02 05:25:46 +00003213 symlinkinfo[buflen] = 0; /* just in case so the caller
3214 does not go off the end of the buffer */
Joe Perchesb6b38f72010-04-21 03:50:45 +00003215 cFYI(1, "readlink result - %s", symlinkinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003216 }
Steve French989c7e52009-05-02 05:32:20 +00003217
Linus Torvalds1da177e2005-04-16 15:20:36 -07003218qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07003219 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003220
3221 /* Note: On -EAGAIN error only caller can retry on handle based calls
3222 since file handle passed in no longer valid */
3223
3224 return rc;
3225}
Steve Frenchc52a9552011-02-24 06:16:22 +00003226#endif /* CIFS_SYMLINK_EXPERIMENTAL */ /* BB temporarily unused */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003227
3228#ifdef CONFIG_CIFS_POSIX
3229
3230/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00003231static void cifs_convert_ace(posix_acl_xattr_entry *ace,
3232 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003233{
3234 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08003235 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
3236 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
3237 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesb6b38f72010-04-21 03:50:45 +00003238 /* cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003239
3240 return;
3241}
3242
3243/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00003244static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
3245 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003246{
3247 int size = 0;
3248 int i;
3249 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00003250 struct cifs_posix_ace *pACE;
3251 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
3252 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003253
3254 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
3255 return -EOPNOTSUPP;
3256
Steve French790fe572007-07-07 19:25:05 +00003257 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003258 count = le16_to_cpu(cifs_acl->access_entry_count);
3259 pACE = &cifs_acl->ace_array[0];
3260 size = sizeof(struct cifs_posix_acl);
3261 size += sizeof(struct cifs_posix_ace) * count;
3262 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003263 if (size_of_data_area < size) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003264 cFYI(1, "bad CIFS POSIX ACL size %d vs. %d",
3265 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003266 return -EINVAL;
3267 }
Steve French790fe572007-07-07 19:25:05 +00003268 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003269 count = le16_to_cpu(cifs_acl->access_entry_count);
3270 size = sizeof(struct cifs_posix_acl);
3271 size += sizeof(struct cifs_posix_ace) * count;
3272/* skip past access ACEs to get to default ACEs */
3273 pACE = &cifs_acl->ace_array[count];
3274 count = le16_to_cpu(cifs_acl->default_entry_count);
3275 size += sizeof(struct cifs_posix_ace) * count;
3276 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003277 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003278 return -EINVAL;
3279 } else {
3280 /* illegal type */
3281 return -EINVAL;
3282 }
3283
3284 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00003285 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00003286 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00003287 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003288 return -ERANGE;
3289 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08003290 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00003291 for (i = 0; i < count ; i++) {
3292 cifs_convert_ace(&local_acl->a_entries[i], pACE);
3293 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003294 }
3295 }
3296 return size;
3297}
3298
Steve French50c2f752007-07-13 00:33:32 +00003299static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
3300 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003301{
3302 __u16 rc = 0; /* 0 = ACL converted ok */
3303
Steve Frenchff7feac2005-11-15 16:45:16 -08003304 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
3305 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003306 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00003307 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003308 /* Probably no need to le convert -1 on any arch but can not hurt */
3309 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00003310 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08003311 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesb6b38f72010-04-21 03:50:45 +00003312 /*cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id);*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003313 return rc;
3314}
3315
3316/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00003317static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
3318 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003319{
3320 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00003321 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
3322 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003323 int count;
3324 int i;
3325
Steve French790fe572007-07-07 19:25:05 +00003326 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003327 return 0;
3328
3329 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesb6b38f72010-04-21 03:50:45 +00003330 cFYI(1, "setting acl with %d entries from buf of length %d and "
Steve French63135e02007-07-17 17:34:02 +00003331 "version of %d",
Joe Perchesb6b38f72010-04-21 03:50:45 +00003332 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00003333 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003334 cFYI(1, "unknown POSIX ACL version %d",
3335 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003336 return 0;
3337 }
3338 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00003339 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08003340 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00003341 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08003342 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003343 else {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003344 cFYI(1, "unknown ACL type %d", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003345 return 0;
3346 }
Steve French50c2f752007-07-13 00:33:32 +00003347 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003348 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
3349 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00003350 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003351 /* ACE not converted */
3352 break;
3353 }
3354 }
Steve French790fe572007-07-07 19:25:05 +00003355 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003356 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
3357 rc += sizeof(struct cifs_posix_acl);
3358 /* BB add check to make sure ACL does not overflow SMB */
3359 }
3360 return rc;
3361}
3362
3363int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003364CIFSSMBGetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003365 const unsigned char *searchName,
3366 char *acl_inf, const int buflen, const int acl_type,
3367 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003368{
3369/* SMB_QUERY_POSIX_ACL */
3370 TRANSACTION2_QPI_REQ *pSMB = NULL;
3371 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3372 int rc = 0;
3373 int bytes_returned;
3374 int name_len;
3375 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00003376
Joe Perchesb6b38f72010-04-21 03:50:45 +00003377 cFYI(1, "In GetPosixACL (Unix) for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003378
3379queryAclRetry:
3380 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3381 (void **) &pSMBr);
3382 if (rc)
3383 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003384
Linus Torvalds1da177e2005-04-16 15:20:36 -07003385 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3386 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003387 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3388 searchName, PATH_MAX, nls_codepage,
3389 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003390 name_len++; /* trailing null */
3391 name_len *= 2;
3392 pSMB->FileName[name_len] = 0;
3393 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00003394 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003395 name_len = strnlen(searchName, PATH_MAX);
3396 name_len++; /* trailing null */
3397 strncpy(pSMB->FileName, searchName, name_len);
3398 }
3399
3400 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3401 pSMB->TotalDataCount = 0;
3402 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00003403 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003404 pSMB->MaxDataCount = cpu_to_le16(4000);
3405 pSMB->MaxSetupCount = 0;
3406 pSMB->Reserved = 0;
3407 pSMB->Flags = 0;
3408 pSMB->Timeout = 0;
3409 pSMB->Reserved2 = 0;
3410 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003411 offsetof(struct smb_com_transaction2_qpi_req,
3412 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003413 pSMB->DataCount = 0;
3414 pSMB->DataOffset = 0;
3415 pSMB->SetupCount = 1;
3416 pSMB->Reserved3 = 0;
3417 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3418 byte_count = params + 1 /* pad */ ;
3419 pSMB->TotalParameterCount = cpu_to_le16(params);
3420 pSMB->ParameterCount = pSMB->TotalParameterCount;
3421 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
3422 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003423 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003424 pSMB->ByteCount = cpu_to_le16(byte_count);
3425
3426 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3427 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003428 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003429 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003430 cFYI(1, "Send error in Query POSIX ACL = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003431 } else {
3432 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00003433
Linus Torvalds1da177e2005-04-16 15:20:36 -07003434 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003435 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003436 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003437 rc = -EIO; /* bad smb */
3438 else {
3439 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3440 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3441 rc = cifs_copy_posix_acl(acl_inf,
3442 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00003443 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003444 }
3445 }
3446 cifs_buf_release(pSMB);
3447 if (rc == -EAGAIN)
3448 goto queryAclRetry;
3449 return rc;
3450}
3451
3452int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003453CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003454 const unsigned char *fileName,
3455 const char *local_acl, const int buflen,
3456 const int acl_type,
3457 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003458{
3459 struct smb_com_transaction2_spi_req *pSMB = NULL;
3460 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3461 char *parm_data;
3462 int name_len;
3463 int rc = 0;
3464 int bytes_returned = 0;
3465 __u16 params, byte_count, data_count, param_offset, offset;
3466
Joe Perchesb6b38f72010-04-21 03:50:45 +00003467 cFYI(1, "In SetPosixACL (Unix) for path %s", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003468setAclRetry:
3469 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003470 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003471 if (rc)
3472 return rc;
3473 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3474 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003475 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
3476 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003477 name_len++; /* trailing null */
3478 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003479 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003480 name_len = strnlen(fileName, PATH_MAX);
3481 name_len++; /* trailing null */
3482 strncpy(pSMB->FileName, fileName, name_len);
3483 }
3484 params = 6 + name_len;
3485 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003486 /* BB find max SMB size from sess */
3487 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003488 pSMB->MaxSetupCount = 0;
3489 pSMB->Reserved = 0;
3490 pSMB->Flags = 0;
3491 pSMB->Timeout = 0;
3492 pSMB->Reserved2 = 0;
3493 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003494 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003495 offset = param_offset + params;
3496 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
3497 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3498
3499 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00003500 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003501
Steve French790fe572007-07-07 19:25:05 +00003502 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003503 rc = -EOPNOTSUPP;
3504 goto setACLerrorExit;
3505 }
3506 pSMB->DataOffset = cpu_to_le16(offset);
3507 pSMB->SetupCount = 1;
3508 pSMB->Reserved3 = 0;
3509 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3510 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
3511 byte_count = 3 /* pad */ + params + data_count;
3512 pSMB->DataCount = cpu_to_le16(data_count);
3513 pSMB->TotalDataCount = pSMB->DataCount;
3514 pSMB->ParameterCount = cpu_to_le16(params);
3515 pSMB->TotalParameterCount = pSMB->ParameterCount;
3516 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003517 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003518 pSMB->ByteCount = cpu_to_le16(byte_count);
3519 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003520 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003521 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003522 cFYI(1, "Set POSIX ACL returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003523
3524setACLerrorExit:
3525 cifs_buf_release(pSMB);
3526 if (rc == -EAGAIN)
3527 goto setAclRetry;
3528 return rc;
3529}
3530
Steve Frenchf654bac2005-04-28 22:41:04 -07003531/* BB fix tabs in this function FIXME BB */
3532int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003533CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00003534 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07003535{
Steve French50c2f752007-07-13 00:33:32 +00003536 int rc = 0;
3537 struct smb_t2_qfi_req *pSMB = NULL;
3538 struct smb_t2_qfi_rsp *pSMBr = NULL;
3539 int bytes_returned;
3540 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07003541
Joe Perchesb6b38f72010-04-21 03:50:45 +00003542 cFYI(1, "In GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00003543 if (tcon == NULL)
3544 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07003545
3546GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003547 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3548 (void **) &pSMBr);
3549 if (rc)
3550 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003551
Steve Frenchad7a2922008-02-07 23:25:02 +00003552 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003553 pSMB->t2.TotalDataCount = 0;
3554 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3555 /* BB find exact max data count below from sess structure BB */
3556 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3557 pSMB->t2.MaxSetupCount = 0;
3558 pSMB->t2.Reserved = 0;
3559 pSMB->t2.Flags = 0;
3560 pSMB->t2.Timeout = 0;
3561 pSMB->t2.Reserved2 = 0;
3562 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3563 Fid) - 4);
3564 pSMB->t2.DataCount = 0;
3565 pSMB->t2.DataOffset = 0;
3566 pSMB->t2.SetupCount = 1;
3567 pSMB->t2.Reserved3 = 0;
3568 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3569 byte_count = params + 1 /* pad */ ;
3570 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3571 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3572 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3573 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003574 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003575 inc_rfc1001_len(pSMB, byte_count);
Steve French790fe572007-07-07 19:25:05 +00003576 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003577
Steve French790fe572007-07-07 19:25:05 +00003578 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3579 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3580 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003581 cFYI(1, "error %d in GetExtAttr", rc);
Steve French790fe572007-07-07 19:25:05 +00003582 } else {
3583 /* decode response */
3584 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003585 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003586 if (rc || get_bcc(&pSMBr->hdr) < 2)
Steve French790fe572007-07-07 19:25:05 +00003587 /* If rc should we check for EOPNOSUPP and
3588 disable the srvino flag? or in caller? */
3589 rc = -EIO; /* bad smb */
3590 else {
3591 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3592 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3593 struct file_chattr_info *pfinfo;
3594 /* BB Do we need a cast or hash here ? */
3595 if (count != 16) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003596 cFYI(1, "Illegal size ret in GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00003597 rc = -EIO;
3598 goto GetExtAttrOut;
3599 }
3600 pfinfo = (struct file_chattr_info *)
3601 (data_offset + (char *) &pSMBr->hdr.Protocol);
3602 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003603 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003604 }
3605 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003606GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003607 cifs_buf_release(pSMB);
3608 if (rc == -EAGAIN)
3609 goto GetExtAttrRetry;
3610 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003611}
3612
Steve Frenchf654bac2005-04-28 22:41:04 -07003613#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003614
Jeff Layton79df1ba2010-12-06 12:52:08 -05003615#ifdef CONFIG_CIFS_ACL
3616/*
3617 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3618 * all NT TRANSACTS that we init here have total parm and data under about 400
3619 * bytes (to fit in small cifs buffer size), which is the case so far, it
3620 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3621 * returned setup area) and MaxParameterCount (returned parms size) must be set
3622 * by caller
3623 */
3624static int
3625smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French96daf2b2011-05-27 04:34:02 +00003626 const int parm_len, struct cifs_tcon *tcon,
Jeff Layton79df1ba2010-12-06 12:52:08 -05003627 void **ret_buf)
3628{
3629 int rc;
3630 __u32 temp_offset;
3631 struct smb_com_ntransact_req *pSMB;
3632
3633 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3634 (void **)&pSMB);
3635 if (rc)
3636 return rc;
3637 *ret_buf = (void *)pSMB;
3638 pSMB->Reserved = 0;
3639 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3640 pSMB->TotalDataCount = 0;
Jeff Laytonc974bef2011-10-11 06:41:32 -04003641 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003642 pSMB->ParameterCount = pSMB->TotalParameterCount;
3643 pSMB->DataCount = pSMB->TotalDataCount;
3644 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3645 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3646 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3647 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3648 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3649 pSMB->SubCommand = cpu_to_le16(sub_command);
3650 return 0;
3651}
3652
3653static int
3654validate_ntransact(char *buf, char **ppparm, char **ppdata,
3655 __u32 *pparmlen, __u32 *pdatalen)
3656{
3657 char *end_of_smb;
3658 __u32 data_count, data_offset, parm_count, parm_offset;
3659 struct smb_com_ntransact_rsp *pSMBr;
Jeff Layton820a8032011-05-04 08:05:26 -04003660 u16 bcc;
Jeff Layton79df1ba2010-12-06 12:52:08 -05003661
3662 *pdatalen = 0;
3663 *pparmlen = 0;
3664
3665 if (buf == NULL)
3666 return -EINVAL;
3667
3668 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3669
Jeff Layton820a8032011-05-04 08:05:26 -04003670 bcc = get_bcc(&pSMBr->hdr);
3671 end_of_smb = 2 /* sizeof byte count */ + bcc +
Jeff Layton79df1ba2010-12-06 12:52:08 -05003672 (char *)&pSMBr->ByteCount;
3673
3674 data_offset = le32_to_cpu(pSMBr->DataOffset);
3675 data_count = le32_to_cpu(pSMBr->DataCount);
3676 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3677 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3678
3679 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3680 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3681
3682 /* should we also check that parm and data areas do not overlap? */
3683 if (*ppparm > end_of_smb) {
3684 cFYI(1, "parms start after end of smb");
3685 return -EINVAL;
3686 } else if (parm_count + *ppparm > end_of_smb) {
3687 cFYI(1, "parm end after end of smb");
3688 return -EINVAL;
3689 } else if (*ppdata > end_of_smb) {
3690 cFYI(1, "data starts after end of smb");
3691 return -EINVAL;
3692 } else if (data_count + *ppdata > end_of_smb) {
3693 cFYI(1, "data %p + count %d (%p) past smb end %p start %p",
3694 *ppdata, data_count, (data_count + *ppdata),
3695 end_of_smb, pSMBr);
3696 return -EINVAL;
Jeff Layton820a8032011-05-04 08:05:26 -04003697 } else if (parm_count + data_count > bcc) {
Jeff Layton79df1ba2010-12-06 12:52:08 -05003698 cFYI(1, "parm count and data count larger than SMB");
3699 return -EINVAL;
3700 }
3701 *pdatalen = data_count;
3702 *pparmlen = parm_count;
3703 return 0;
3704}
3705
Steve French0a4b92c2006-01-12 15:44:21 -08003706/* Get Security Descriptor (by handle) from remote server for a file or dir */
3707int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003708CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003709 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003710{
3711 int rc = 0;
3712 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003713 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003714 struct kvec iov[1];
3715
Joe Perchesb6b38f72010-04-21 03:50:45 +00003716 cFYI(1, "GetCifsACL");
Steve French0a4b92c2006-01-12 15:44:21 -08003717
Steve French630f3f0c2007-10-25 21:17:17 +00003718 *pbuflen = 0;
3719 *acl_inf = NULL;
3720
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003721 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003722 8 /* parm len */, tcon, (void **) &pSMB);
3723 if (rc)
3724 return rc;
3725
3726 pSMB->MaxParameterCount = cpu_to_le32(4);
3727 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3728 pSMB->MaxSetupCount = 0;
3729 pSMB->Fid = fid; /* file handle always le */
3730 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3731 CIFS_ACL_DACL);
3732 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003733 inc_rfc1001_len(pSMB, 11);
Steve French0a4b92c2006-01-12 15:44:21 -08003734 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003735 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French0a4b92c2006-01-12 15:44:21 -08003736
Steve Frencha761ac52007-10-18 21:45:27 +00003737 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Jeff Layton77499812011-01-11 07:24:23 -05003738 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003739 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Steve French0a4b92c2006-01-12 15:44:21 -08003740 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003741 cFYI(1, "Send error in QuerySecDesc = %d", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08003742 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003743 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003744 __u32 parm_len;
3745 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003746 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003747 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003748
3749/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003750 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003751 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003752 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003753 goto qsec_out;
3754 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3755
Joe Perchesb6b38f72010-04-21 03:50:45 +00003756 cFYI(1, "smb %p parm %p data %p", pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08003757
3758 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3759 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003760 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003761 goto qsec_out;
3762 }
3763
3764/* BB check that data area is minimum length and as big as acl_len */
3765
Steve Frenchaf6f4612007-10-16 18:40:37 +00003766 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003767 if (acl_len != *pbuflen) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003768 cERROR(1, "acl length %d does not match %d",
3769 acl_len, *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003770 if (*pbuflen > acl_len)
3771 *pbuflen = acl_len;
3772 }
Steve French0a4b92c2006-01-12 15:44:21 -08003773
Steve French630f3f0c2007-10-25 21:17:17 +00003774 /* check if buffer is big enough for the acl
3775 header followed by the smallest SID */
3776 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3777 (*pbuflen >= 64 * 1024)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003778 cERROR(1, "bad acl length %d", *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003779 rc = -EINVAL;
3780 *pbuflen = 0;
3781 } else {
3782 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3783 if (*acl_inf == NULL) {
3784 *pbuflen = 0;
3785 rc = -ENOMEM;
3786 }
3787 memcpy(*acl_inf, pdata, *pbuflen);
3788 }
Steve French0a4b92c2006-01-12 15:44:21 -08003789 }
3790qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003791 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003792 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003793 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003794 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003795/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003796 return rc;
3797}
Steve French97837582007-12-31 07:47:21 +00003798
3799int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003800CIFSSMBSetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003801 struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
Steve French97837582007-12-31 07:47:21 +00003802{
3803 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3804 int rc = 0;
3805 int bytes_returned = 0;
3806 SET_SEC_DESC_REQ *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003807 void *pSMBr;
Steve French97837582007-12-31 07:47:21 +00003808
3809setCifsAclRetry:
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003810 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, &pSMBr);
Steve French97837582007-12-31 07:47:21 +00003811 if (rc)
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003812 return rc;
Steve French97837582007-12-31 07:47:21 +00003813
3814 pSMB->MaxSetupCount = 0;
3815 pSMB->Reserved = 0;
3816
3817 param_count = 8;
3818 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3819 data_count = acllen;
3820 data_offset = param_offset + param_count;
3821 byte_count = 3 /* pad */ + param_count;
3822
3823 pSMB->DataCount = cpu_to_le32(data_count);
3824 pSMB->TotalDataCount = pSMB->DataCount;
3825 pSMB->MaxParameterCount = cpu_to_le32(4);
3826 pSMB->MaxDataCount = cpu_to_le32(16384);
3827 pSMB->ParameterCount = cpu_to_le32(param_count);
3828 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3829 pSMB->TotalParameterCount = pSMB->ParameterCount;
3830 pSMB->DataOffset = cpu_to_le32(data_offset);
3831 pSMB->SetupCount = 0;
3832 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3833 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3834
3835 pSMB->Fid = fid; /* file handle always le */
3836 pSMB->Reserved2 = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003837 pSMB->AclFlags = cpu_to_le32(aclflag);
Steve French97837582007-12-31 07:47:21 +00003838
3839 if (pntsd && acllen) {
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003840 memcpy((char *)pSMBr + offsetof(struct smb_hdr, Protocol) +
3841 data_offset, pntsd, acllen);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003842 inc_rfc1001_len(pSMB, byte_count + data_count);
Steve French97837582007-12-31 07:47:21 +00003843 } else
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003844 inc_rfc1001_len(pSMB, byte_count);
Steve French97837582007-12-31 07:47:21 +00003845
3846 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3847 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3848
Joe Perchesb6b38f72010-04-21 03:50:45 +00003849 cFYI(1, "SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00003850 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003851 cFYI(1, "Set CIFS ACL returned %d", rc);
Steve French97837582007-12-31 07:47:21 +00003852 cifs_buf_release(pSMB);
3853
3854 if (rc == -EAGAIN)
3855 goto setCifsAclRetry;
3856
3857 return (rc);
3858}
3859
Jeff Layton79df1ba2010-12-06 12:52:08 -05003860#endif /* CONFIG_CIFS_ACL */
Steve French0a4b92c2006-01-12 15:44:21 -08003861
Steve French6b8edfe2005-08-23 20:26:03 -07003862/* Legacy Query Path Information call for lookup to old servers such
3863 as Win9x/WinME */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003864int
3865SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon,
3866 const char *search_name, FILE_ALL_INFO *data,
3867 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003868{
Steve Frenchad7a2922008-02-07 23:25:02 +00003869 QUERY_INFORMATION_REQ *pSMB;
3870 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003871 int rc = 0;
3872 int bytes_returned;
3873 int name_len;
3874
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003875 cFYI(1, "In SMBQPath path %s", search_name);
Steve French6b8edfe2005-08-23 20:26:03 -07003876QInfRetry:
3877 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003878 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003879 if (rc)
3880 return rc;
3881
3882 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3883 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003884 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003885 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06003886 remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003887 name_len++; /* trailing null */
3888 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003889 } else {
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003890 name_len = strnlen(search_name, PATH_MAX);
Steve French6b8edfe2005-08-23 20:26:03 -07003891 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003892 strncpy(pSMB->FileName, search_name, name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07003893 }
3894 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003895 name_len++; /* account for buffer type byte */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003896 inc_rfc1001_len(pSMB, (__u16)name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07003897 pSMB->ByteCount = cpu_to_le16(name_len);
3898
3899 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003900 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003901 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003902 cFYI(1, "Send error in QueryInfo = %d", rc);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003903 } else if (data) {
Steve French1bd5bbc2006-09-28 03:35:57 +00003904 struct timespec ts;
3905 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00003906
3907 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003908 /* BB FIXME - add time zone adjustment BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003909 memset(data, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003910 ts.tv_nsec = 0;
3911 ts.tv_sec = time;
3912 /* decode time fields */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003913 data->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
3914 data->LastWriteTime = data->ChangeTime;
3915 data->LastAccessTime = 0;
3916 data->AllocationSize =
Steve French70ca7342005-09-22 16:32:06 -07003917 cpu_to_le64(le32_to_cpu(pSMBr->size));
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003918 data->EndOfFile = data->AllocationSize;
3919 data->Attributes =
Steve French70ca7342005-09-22 16:32:06 -07003920 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003921 } else
3922 rc = -EIO; /* bad buffer passed in */
3923
3924 cifs_buf_release(pSMB);
3925
3926 if (rc == -EAGAIN)
3927 goto QInfRetry;
3928
3929 return rc;
3930}
3931
Jeff Laytonbcd53572010-02-12 07:44:16 -05003932int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003933CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonbcd53572010-02-12 07:44:16 -05003934 u16 netfid, FILE_ALL_INFO *pFindData)
3935{
3936 struct smb_t2_qfi_req *pSMB = NULL;
3937 struct smb_t2_qfi_rsp *pSMBr = NULL;
3938 int rc = 0;
3939 int bytes_returned;
3940 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07003941
Jeff Laytonbcd53572010-02-12 07:44:16 -05003942QFileInfoRetry:
3943 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3944 (void **) &pSMBr);
3945 if (rc)
3946 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07003947
Jeff Laytonbcd53572010-02-12 07:44:16 -05003948 params = 2 /* level */ + 2 /* fid */;
3949 pSMB->t2.TotalDataCount = 0;
3950 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3951 /* BB find exact max data count below from sess structure BB */
3952 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3953 pSMB->t2.MaxSetupCount = 0;
3954 pSMB->t2.Reserved = 0;
3955 pSMB->t2.Flags = 0;
3956 pSMB->t2.Timeout = 0;
3957 pSMB->t2.Reserved2 = 0;
3958 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3959 Fid) - 4);
3960 pSMB->t2.DataCount = 0;
3961 pSMB->t2.DataOffset = 0;
3962 pSMB->t2.SetupCount = 1;
3963 pSMB->t2.Reserved3 = 0;
3964 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3965 byte_count = params + 1 /* pad */ ;
3966 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3967 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3968 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3969 pSMB->Pad = 0;
3970 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003971 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003972
3973 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3974 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3975 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00003976 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003977 } else { /* decode response */
3978 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3979
3980 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3981 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04003982 else if (get_bcc(&pSMBr->hdr) < 40)
Jeff Laytonbcd53572010-02-12 07:44:16 -05003983 rc = -EIO; /* bad smb */
3984 else if (pFindData) {
3985 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3986 memcpy((char *) pFindData,
3987 (char *) &pSMBr->hdr.Protocol +
3988 data_offset, sizeof(FILE_ALL_INFO));
3989 } else
3990 rc = -ENOMEM;
3991 }
3992 cifs_buf_release(pSMB);
3993 if (rc == -EAGAIN)
3994 goto QFileInfoRetry;
3995
3996 return rc;
3997}
Steve French6b8edfe2005-08-23 20:26:03 -07003998
Linus Torvalds1da177e2005-04-16 15:20:36 -07003999int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004000CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004001 const char *search_name, FILE_ALL_INFO *data,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004002 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07004003 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004004{
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004005 /* level 263 SMB_QUERY_FILE_ALL_INFO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004006 TRANSACTION2_QPI_REQ *pSMB = NULL;
4007 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4008 int rc = 0;
4009 int bytes_returned;
4010 int name_len;
4011 __u16 params, byte_count;
4012
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004013 /* cFYI(1, "In QPathInfo path %s", search_name); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004014QPathInfoRetry:
4015 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4016 (void **) &pSMBr);
4017 if (rc)
4018 return rc;
4019
4020 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4021 name_len =
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004022 cifsConvertToUTF16((__le16 *) pSMB->FileName, search_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06004023 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004024 name_len++; /* trailing null */
4025 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004026 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004027 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004028 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004029 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004030 }
4031
Steve French50c2f752007-07-13 00:33:32 +00004032 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004033 pSMB->TotalDataCount = 0;
4034 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004035 /* BB find exact max SMB PDU from sess structure BB */
4036 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004037 pSMB->MaxSetupCount = 0;
4038 pSMB->Reserved = 0;
4039 pSMB->Flags = 0;
4040 pSMB->Timeout = 0;
4041 pSMB->Reserved2 = 0;
4042 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004043 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004044 pSMB->DataCount = 0;
4045 pSMB->DataOffset = 0;
4046 pSMB->SetupCount = 1;
4047 pSMB->Reserved3 = 0;
4048 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4049 byte_count = params + 1 /* pad */ ;
4050 pSMB->TotalParameterCount = cpu_to_le16(params);
4051 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00004052 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004053 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
4054 else
4055 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004056 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004057 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004058 pSMB->ByteCount = cpu_to_le16(byte_count);
4059
4060 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4061 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4062 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004063 cFYI(1, "Send error in QPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004064 } else { /* decode response */
4065 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4066
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004067 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4068 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004069 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004070 rc = -EIO; /* bad smb */
Jeff Layton820a8032011-05-04 08:05:26 -04004071 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
Steve French50c2f752007-07-13 00:33:32 +00004072 rc = -EIO; /* 24 or 26 expected but we do not read
4073 last field */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004074 else if (data) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004075 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004076 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00004077
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004078 /*
4079 * On legacy responses we do not read the last field,
4080 * EAsize, fortunately since it varies by subdialect and
4081 * also note it differs on Set vs Get, ie two bytes or 4
4082 * bytes depending but we don't care here.
4083 */
Steve Frenchad7a2922008-02-07 23:25:02 +00004084 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004085 size = sizeof(FILE_INFO_STANDARD);
4086 else
4087 size = sizeof(FILE_ALL_INFO);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004088 memcpy((char *) data, (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004089 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004090 } else
4091 rc = -ENOMEM;
4092 }
4093 cifs_buf_release(pSMB);
4094 if (rc == -EAGAIN)
4095 goto QPathInfoRetry;
4096
4097 return rc;
4098}
4099
4100int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004101CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004102 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
4103{
4104 struct smb_t2_qfi_req *pSMB = NULL;
4105 struct smb_t2_qfi_rsp *pSMBr = NULL;
4106 int rc = 0;
4107 int bytes_returned;
4108 __u16 params, byte_count;
4109
4110UnixQFileInfoRetry:
4111 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4112 (void **) &pSMBr);
4113 if (rc)
4114 return rc;
4115
4116 params = 2 /* level */ + 2 /* fid */;
4117 pSMB->t2.TotalDataCount = 0;
4118 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4119 /* BB find exact max data count below from sess structure BB */
4120 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4121 pSMB->t2.MaxSetupCount = 0;
4122 pSMB->t2.Reserved = 0;
4123 pSMB->t2.Flags = 0;
4124 pSMB->t2.Timeout = 0;
4125 pSMB->t2.Reserved2 = 0;
4126 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4127 Fid) - 4);
4128 pSMB->t2.DataCount = 0;
4129 pSMB->t2.DataOffset = 0;
4130 pSMB->t2.SetupCount = 1;
4131 pSMB->t2.Reserved3 = 0;
4132 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4133 byte_count = params + 1 /* pad */ ;
4134 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4135 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4136 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4137 pSMB->Pad = 0;
4138 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004139 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004140
4141 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4142 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4143 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00004144 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004145 } else { /* decode response */
4146 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4147
Jeff Layton820a8032011-05-04 08:05:26 -04004148 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004149 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response. "
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004150 "Unix Extensions can be disabled on mount "
Steve Frenchf19159d2010-04-21 04:12:10 +00004151 "by specifying the nosfu mount option.");
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004152 rc = -EIO; /* bad smb */
4153 } else {
4154 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4155 memcpy((char *) pFindData,
4156 (char *) &pSMBr->hdr.Protocol +
4157 data_offset,
4158 sizeof(FILE_UNIX_BASIC_INFO));
4159 }
4160 }
4161
4162 cifs_buf_release(pSMB);
4163 if (rc == -EAGAIN)
4164 goto UnixQFileInfoRetry;
4165
4166 return rc;
4167}
4168
4169int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004170CIFSSMBUnixQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004171 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00004172 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07004173 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004174{
4175/* SMB_QUERY_FILE_UNIX_BASIC */
4176 TRANSACTION2_QPI_REQ *pSMB = NULL;
4177 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4178 int rc = 0;
4179 int bytes_returned = 0;
4180 int name_len;
4181 __u16 params, byte_count;
4182
Joe Perchesb6b38f72010-04-21 03:50:45 +00004183 cFYI(1, "In QPathInfo (Unix) the path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004184UnixQPathInfoRetry:
4185 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4186 (void **) &pSMBr);
4187 if (rc)
4188 return rc;
4189
4190 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4191 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004192 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4193 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004194 name_len++; /* trailing null */
4195 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004196 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004197 name_len = strnlen(searchName, PATH_MAX);
4198 name_len++; /* trailing null */
4199 strncpy(pSMB->FileName, searchName, name_len);
4200 }
4201
Steve French50c2f752007-07-13 00:33:32 +00004202 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004203 pSMB->TotalDataCount = 0;
4204 pSMB->MaxParameterCount = cpu_to_le16(2);
4205 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00004206 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004207 pSMB->MaxSetupCount = 0;
4208 pSMB->Reserved = 0;
4209 pSMB->Flags = 0;
4210 pSMB->Timeout = 0;
4211 pSMB->Reserved2 = 0;
4212 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004213 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004214 pSMB->DataCount = 0;
4215 pSMB->DataOffset = 0;
4216 pSMB->SetupCount = 1;
4217 pSMB->Reserved3 = 0;
4218 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4219 byte_count = params + 1 /* pad */ ;
4220 pSMB->TotalParameterCount = cpu_to_le16(params);
4221 pSMB->ParameterCount = pSMB->TotalParameterCount;
4222 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4223 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004224 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004225 pSMB->ByteCount = cpu_to_le16(byte_count);
4226
4227 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4228 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4229 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004230 cFYI(1, "Send error in QPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004231 } else { /* decode response */
4232 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4233
Jeff Layton820a8032011-05-04 08:05:26 -04004234 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004235 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response. "
Steve French1e71f252007-09-20 15:30:07 +00004236 "Unix Extensions can be disabled on mount "
Joe Perchesb6b38f72010-04-21 03:50:45 +00004237 "by specifying the nosfu mount option.");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004238 rc = -EIO; /* bad smb */
4239 } else {
4240 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4241 memcpy((char *) pFindData,
4242 (char *) &pSMBr->hdr.Protocol +
4243 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00004244 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004245 }
4246 }
4247 cifs_buf_release(pSMB);
4248 if (rc == -EAGAIN)
4249 goto UnixQPathInfoRetry;
4250
4251 return rc;
4252}
4253
Linus Torvalds1da177e2005-04-16 15:20:36 -07004254/* xid, tcon, searchName and codepage are input parms, rest are returned */
4255int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004256CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004257 const char *searchName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004258 const struct nls_table *nls_codepage,
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004259 __u16 *pnetfid, __u16 search_flags,
Steve French50c2f752007-07-13 00:33:32 +00004260 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004261{
4262/* level 257 SMB_ */
4263 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
4264 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004265 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004266 int rc = 0;
4267 int bytes_returned = 0;
4268 int name_len;
4269 __u16 params, byte_count;
4270
Joe Perchesb6b38f72010-04-21 03:50:45 +00004271 cFYI(1, "In FindFirst for %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004272
4273findFirstRetry:
4274 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4275 (void **) &pSMBr);
4276 if (rc)
4277 return rc;
4278
4279 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4280 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004281 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4282 PATH_MAX, nls_codepage, remap);
Steve French737b7582005-04-28 22:41:06 -07004283 /* We can not add the asterik earlier in case
4284 it got remapped to 0xF03A as if it were part of the
4285 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004286 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07004287 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07004288 pSMB->FileName[name_len+1] = 0;
4289 pSMB->FileName[name_len+2] = '*';
4290 pSMB->FileName[name_len+3] = 0;
4291 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004292 pSMB->FileName[name_len] = 0; /* null terminate just in case */
4293 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07004294 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004295 } else { /* BB add check for overrun of SMB buf BB */
4296 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004297/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00004298 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004299 free buffer exit; BB */
4300 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07004301 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07004302 pSMB->FileName[name_len+1] = '*';
4303 pSMB->FileName[name_len+2] = 0;
4304 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004305 }
4306
4307 params = 12 + name_len /* includes null */ ;
4308 pSMB->TotalDataCount = 0; /* no EAs */
4309 pSMB->MaxParameterCount = cpu_to_le16(10);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004310 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004311 pSMB->MaxSetupCount = 0;
4312 pSMB->Reserved = 0;
4313 pSMB->Flags = 0;
4314 pSMB->Timeout = 0;
4315 pSMB->Reserved2 = 0;
4316 byte_count = params + 1 /* pad */ ;
4317 pSMB->TotalParameterCount = cpu_to_le16(params);
4318 pSMB->ParameterCount = pSMB->TotalParameterCount;
4319 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00004320 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
4321 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004322 pSMB->DataCount = 0;
4323 pSMB->DataOffset = 0;
4324 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
4325 pSMB->Reserved3 = 0;
4326 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
4327 pSMB->SearchAttributes =
4328 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
4329 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00004330 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004331 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004332 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4333
4334 /* BB what should we set StorageType to? Does it matter? BB */
4335 pSMB->SearchStorageType = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004336 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004337 pSMB->ByteCount = cpu_to_le16(byte_count);
4338
4339 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4340 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004341 cifs_stats_inc(&tcon->stats.cifs_stats.num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004342
Steve French88274812006-03-09 22:21:45 +00004343 if (rc) {/* BB add logic to retry regular search if Unix search
4344 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004345 /* BB Add code to handle unsupported level rc */
Joe Perchesb6b38f72010-04-21 03:50:45 +00004346 cFYI(1, "Error in FindFirst = %d", rc);
Steve French1982c342005-08-17 12:38:22 -07004347
Steve French88274812006-03-09 22:21:45 +00004348 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004349
4350 /* BB eventually could optimize out free and realloc of buf */
4351 /* for this case */
4352 if (rc == -EAGAIN)
4353 goto findFirstRetry;
4354 } else { /* decode response */
4355 /* BB remember to free buffer if error BB */
4356 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00004357 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004358 unsigned int lnoff;
4359
Linus Torvalds1da177e2005-04-16 15:20:36 -07004360 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004361 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004362 else
Steve French4b18f2a2008-04-29 00:06:05 +00004363 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004364
4365 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004366 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00004367 psrch_inf->srch_entries_start =
4368 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004369 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004370 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
4371 le16_to_cpu(pSMBr->t2.ParameterOffset));
4372
Steve French790fe572007-07-07 19:25:05 +00004373 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004374 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004375 else
Steve French4b18f2a2008-04-29 00:06:05 +00004376 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004377
Steve French50c2f752007-07-13 00:33:32 +00004378 psrch_inf->entries_in_buffer =
4379 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00004380 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004381 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004382 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004383 if (CIFSMaxBufSize < lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004384 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00004385 psrch_inf->last_entry = NULL;
4386 return rc;
4387 }
4388
Steve French0752f152008-10-07 20:03:33 +00004389 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00004390 lnoff;
4391
Linus Torvalds1da177e2005-04-16 15:20:36 -07004392 *pnetfid = parms->SearchHandle;
4393 } else {
4394 cifs_buf_release(pSMB);
4395 }
4396 }
4397
4398 return rc;
4399}
4400
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004401int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
4402 __u16 searchHandle, __u16 search_flags,
4403 struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004404{
4405 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
4406 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004407 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004408 char *response_data;
4409 int rc = 0;
Jeff Layton9438fab2011-08-23 07:21:28 -04004410 int bytes_returned;
4411 unsigned int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004412 __u16 params, byte_count;
4413
Joe Perchesb6b38f72010-04-21 03:50:45 +00004414 cFYI(1, "In FindNext");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004415
Steve French4b18f2a2008-04-29 00:06:05 +00004416 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004417 return -ENOENT;
4418
4419 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4420 (void **) &pSMBr);
4421 if (rc)
4422 return rc;
4423
Steve French50c2f752007-07-13 00:33:32 +00004424 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004425 byte_count = 0;
4426 pSMB->TotalDataCount = 0; /* no EAs */
4427 pSMB->MaxParameterCount = cpu_to_le16(8);
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 pSMB->ParameterOffset = cpu_to_le16(
4435 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
4436 pSMB->DataCount = 0;
4437 pSMB->DataOffset = 0;
4438 pSMB->SetupCount = 1;
4439 pSMB->Reserved3 = 0;
4440 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
4441 pSMB->SearchHandle = searchHandle; /* always kept as le */
4442 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00004443 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004444 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4445 pSMB->ResumeKey = psrch_inf->resume_key;
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004446 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004447
4448 name_len = psrch_inf->resume_name_len;
4449 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00004450 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004451 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
4452 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07004453 /* 14 byte parm len above enough for 2 byte null terminator */
4454 pSMB->ResumeFileName[name_len] = 0;
4455 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004456 } else {
4457 rc = -EINVAL;
4458 goto FNext2_err_exit;
4459 }
4460 byte_count = params + 1 /* pad */ ;
4461 pSMB->TotalParameterCount = cpu_to_le16(params);
4462 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004463 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004464 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004465
Linus Torvalds1da177e2005-04-16 15:20:36 -07004466 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4467 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004468 cifs_stats_inc(&tcon->stats.cifs_stats.num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004469 if (rc) {
4470 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00004471 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07004472 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00004473 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004474 } else
Joe Perchesb6b38f72010-04-21 03:50:45 +00004475 cFYI(1, "FindNext returned = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004476 } else { /* decode response */
4477 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00004478
Steve French790fe572007-07-07 19:25:05 +00004479 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004480 unsigned int lnoff;
4481
Linus Torvalds1da177e2005-04-16 15:20:36 -07004482 /* BB fixme add lock for file (srch_info) struct here */
4483 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004484 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004485 else
Steve French4b18f2a2008-04-29 00:06:05 +00004486 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004487 response_data = (char *) &pSMBr->hdr.Protocol +
4488 le16_to_cpu(pSMBr->t2.ParameterOffset);
4489 parms = (T2_FNEXT_RSP_PARMS *)response_data;
4490 response_data = (char *)&pSMBr->hdr.Protocol +
4491 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00004492 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00004493 cifs_small_buf_release(
4494 psrch_inf->ntwrk_buf_start);
4495 else
4496 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004497 psrch_inf->srch_entries_start = response_data;
4498 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004499 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00004500 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004501 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004502 else
Steve French4b18f2a2008-04-29 00:06:05 +00004503 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00004504 psrch_inf->entries_in_buffer =
4505 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004506 psrch_inf->index_of_last_entry +=
4507 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004508 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004509 if (CIFSMaxBufSize < lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004510 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00004511 psrch_inf->last_entry = NULL;
4512 return rc;
4513 } else
4514 psrch_inf->last_entry =
4515 psrch_inf->srch_entries_start + lnoff;
4516
Joe Perchesb6b38f72010-04-21 03:50:45 +00004517/* cFYI(1, "fnxt2 entries in buf %d index_of_last %d",
4518 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004519
4520 /* BB fixme add unlock here */
4521 }
4522
4523 }
4524
4525 /* BB On error, should we leave previous search buf (and count and
4526 last entry fields) intact or free the previous one? */
4527
4528 /* Note: On -EAGAIN error only caller can retry on handle based calls
4529 since file handle passed in no longer valid */
4530FNext2_err_exit:
4531 if (rc != 0)
4532 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004533 return rc;
4534}
4535
4536int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004537CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004538 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004539{
4540 int rc = 0;
4541 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004542
Joe Perchesb6b38f72010-04-21 03:50:45 +00004543 cFYI(1, "In CIFSSMBFindClose");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004544 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
4545
4546 /* no sense returning error if session restarted
4547 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00004548 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004549 return 0;
4550 if (rc)
4551 return rc;
4552
Linus Torvalds1da177e2005-04-16 15:20:36 -07004553 pSMB->FileID = searchHandle;
4554 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04004555 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004556 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00004557 cERROR(1, "Send error in FindClose = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00004558
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004559 cifs_stats_inc(&tcon->stats.cifs_stats.num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004560
4561 /* Since session is dead, search handle closed on server already */
4562 if (rc == -EAGAIN)
4563 rc = 0;
4564
4565 return rc;
4566}
4567
Linus Torvalds1da177e2005-04-16 15:20:36 -07004568int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004569CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004570 const char *search_name, __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00004571 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004572{
4573 int rc = 0;
4574 TRANSACTION2_QPI_REQ *pSMB = NULL;
4575 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4576 int name_len, bytes_returned;
4577 __u16 params, byte_count;
4578
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004579 cFYI(1, "In GetSrvInodeNum for %s", search_name);
Steve French790fe572007-07-07 19:25:05 +00004580 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00004581 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004582
4583GetInodeNumberRetry:
4584 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004585 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004586 if (rc)
4587 return rc;
4588
Linus Torvalds1da177e2005-04-16 15:20:36 -07004589 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4590 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004591 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004592 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004593 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004594 name_len++; /* trailing null */
4595 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004596 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004597 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004598 name_len++; /* trailing null */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004599 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004600 }
4601
4602 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4603 pSMB->TotalDataCount = 0;
4604 pSMB->MaxParameterCount = cpu_to_le16(2);
4605 /* BB find exact max data count below from sess structure BB */
4606 pSMB->MaxDataCount = cpu_to_le16(4000);
4607 pSMB->MaxSetupCount = 0;
4608 pSMB->Reserved = 0;
4609 pSMB->Flags = 0;
4610 pSMB->Timeout = 0;
4611 pSMB->Reserved2 = 0;
4612 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004613 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004614 pSMB->DataCount = 0;
4615 pSMB->DataOffset = 0;
4616 pSMB->SetupCount = 1;
4617 pSMB->Reserved3 = 0;
4618 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4619 byte_count = params + 1 /* pad */ ;
4620 pSMB->TotalParameterCount = cpu_to_le16(params);
4621 pSMB->ParameterCount = pSMB->TotalParameterCount;
4622 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4623 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004624 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004625 pSMB->ByteCount = cpu_to_le16(byte_count);
4626
4627 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4628 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4629 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004630 cFYI(1, "error %d in QueryInternalInfo", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004631 } else {
4632 /* decode response */
4633 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004634 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04004635 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004636 /* If rc should we check for EOPNOSUPP and
4637 disable the srvino flag? or in caller? */
4638 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00004639 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004640 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4641 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00004642 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004643 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00004644 if (count < 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004645 cFYI(1, "Illegal size ret in QryIntrnlInf");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004646 rc = -EIO;
4647 goto GetInodeNumOut;
4648 }
4649 pfinfo = (struct file_internal_info *)
4650 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00004651 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004652 }
4653 }
4654GetInodeNumOut:
4655 cifs_buf_release(pSMB);
4656 if (rc == -EAGAIN)
4657 goto GetInodeNumberRetry;
4658 return rc;
4659}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004660
Igor Mammedovfec45852008-05-16 13:06:30 +04004661/* parses DFS refferal V3 structure
4662 * caller is responsible for freeing target_nodes
4663 * returns:
4664 * on success - 0
4665 * on failure - errno
4666 */
4667static int
Steve Frencha1fe78f2008-05-16 18:48:38 +00004668parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
Igor Mammedovfec45852008-05-16 13:06:30 +04004669 unsigned int *num_of_nodes,
4670 struct dfs_info3_param **target_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004671 const struct nls_table *nls_codepage, int remap,
4672 const char *searchName)
Igor Mammedovfec45852008-05-16 13:06:30 +04004673{
4674 int i, rc = 0;
4675 char *data_end;
4676 bool is_unicode;
4677 struct dfs_referral_level_3 *ref;
4678
Harvey Harrison5ca33c62008-07-23 17:45:58 -07004679 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4680 is_unicode = true;
4681 else
4682 is_unicode = false;
Igor Mammedovfec45852008-05-16 13:06:30 +04004683 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
4684
4685 if (*num_of_nodes < 1) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004686 cERROR(1, "num_referrals: must be at least > 0,"
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004687 "but we get num_referrals = %d", *num_of_nodes);
Igor Mammedovfec45852008-05-16 13:06:30 +04004688 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004689 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004690 }
4691
4692 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
Al Viro1d92cfd2008-06-02 10:59:02 +01004693 if (ref->VersionNumber != cpu_to_le16(3)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004694 cERROR(1, "Referrals of V%d version are not supported,"
4695 "should be V3", le16_to_cpu(ref->VersionNumber));
Igor Mammedovfec45852008-05-16 13:06:30 +04004696 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004697 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004698 }
4699
4700 /* get the upper boundary of the resp buffer */
4701 data_end = (char *)(&(pSMBr->PathConsumed)) +
4702 le16_to_cpu(pSMBr->t2.DataCount);
4703
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004704 cFYI(1, "num_referrals: %d dfs flags: 0x%x ...",
Igor Mammedovfec45852008-05-16 13:06:30 +04004705 *num_of_nodes,
Joe Perchesb6b38f72010-04-21 03:50:45 +00004706 le32_to_cpu(pSMBr->DFSFlags));
Igor Mammedovfec45852008-05-16 13:06:30 +04004707
4708 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
4709 *num_of_nodes, GFP_KERNEL);
4710 if (*target_nodes == NULL) {
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004711 cERROR(1, "Failed to allocate buffer for target_nodes");
Igor Mammedovfec45852008-05-16 13:06:30 +04004712 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004713 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004714 }
4715
Daniel Mack3ad2f3f2010-02-03 08:01:28 +08004716 /* collect necessary data from referrals */
Igor Mammedovfec45852008-05-16 13:06:30 +04004717 for (i = 0; i < *num_of_nodes; i++) {
4718 char *temp;
4719 int max_len;
4720 struct dfs_info3_param *node = (*target_nodes)+i;
4721
Steve French0e0d2cf2009-05-01 05:27:32 +00004722 node->flags = le32_to_cpu(pSMBr->DFSFlags);
Igor Mammedov2c556082008-10-23 13:58:42 +04004723 if (is_unicode) {
Jeff Layton331c3132008-12-17 06:31:53 -05004724 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4725 GFP_KERNEL);
Steve French2920ee22009-08-31 15:27:26 +00004726 if (tmp == NULL) {
4727 rc = -ENOMEM;
4728 goto parse_DFS_referrals_exit;
4729 }
Steve Frenchacbbb762012-01-18 22:32:33 -06004730 cifsConvertToUTF16((__le16 *) tmp, searchName,
4731 PATH_MAX, nls_codepage, remap);
4732 node->path_consumed = cifs_utf16_bytes(tmp,
Jeff Layton69f801f2009-04-30 06:46:32 -04004733 le16_to_cpu(pSMBr->PathConsumed),
Igor Mammedov2c556082008-10-23 13:58:42 +04004734 nls_codepage);
4735 kfree(tmp);
4736 } else
4737 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4738
Igor Mammedovfec45852008-05-16 13:06:30 +04004739 node->server_type = le16_to_cpu(ref->ServerType);
4740 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4741
4742 /* copy DfsPath */
4743 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4744 max_len = data_end - temp;
Steve Frenchacbbb762012-01-18 22:32:33 -06004745 node->path_name = cifs_strndup_from_utf16(temp, max_len,
4746 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004747 if (!node->path_name) {
4748 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004749 goto parse_DFS_referrals_exit;
Jeff Layton066ce682009-04-30 07:16:14 -04004750 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004751
4752 /* copy link target UNC */
4753 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4754 max_len = data_end - temp;
Steve Frenchacbbb762012-01-18 22:32:33 -06004755 node->node_name = cifs_strndup_from_utf16(temp, max_len,
4756 is_unicode, nls_codepage);
Stefan Metzmacherd8f27992012-05-04 00:19:28 +02004757 if (!node->node_name) {
Jeff Laytond8e2f532009-05-14 07:46:59 -04004758 rc = -ENOMEM;
Stefan Metzmacherd8f27992012-05-04 00:19:28 +02004759 goto parse_DFS_referrals_exit;
4760 }
4761
4762 ref++;
Igor Mammedovfec45852008-05-16 13:06:30 +04004763 }
4764
Steve Frencha1fe78f2008-05-16 18:48:38 +00004765parse_DFS_referrals_exit:
Igor Mammedovfec45852008-05-16 13:06:30 +04004766 if (rc) {
4767 free_dfs_info_array(*target_nodes, *num_of_nodes);
4768 *target_nodes = NULL;
4769 *num_of_nodes = 0;
4770 }
4771 return rc;
4772}
4773
Linus Torvalds1da177e2005-04-16 15:20:36 -07004774int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004775CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004776 const char *search_name, struct dfs_info3_param **target_nodes,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004777 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004778 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004779{
4780/* TRANS2_GET_DFS_REFERRAL */
4781 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4782 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004783 int rc = 0;
4784 int bytes_returned;
4785 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004786 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004787 *num_of_nodes = 0;
4788 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004789
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004790 cFYI(1, "In GetDFSRefer the path %s", search_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004791 if (ses == NULL)
4792 return -ENODEV;
4793getDFSRetry:
4794 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4795 (void **) &pSMBr);
4796 if (rc)
4797 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004798
4799 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004800 but should never be null here anyway */
Pavel Shilovsky88257362012-05-23 14:01:59 +04004801 pSMB->hdr.Mid = get_next_mid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004802 pSMB->hdr.Tid = ses->ipc_tid;
4803 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004804 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004805 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004806 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004807 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004808
4809 if (ses->capabilities & CAP_UNICODE) {
4810 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4811 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004812 cifsConvertToUTF16((__le16 *) pSMB->RequestFileName,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004813 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004814 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004815 name_len++; /* trailing null */
4816 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004817 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004818 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004819 name_len++; /* trailing null */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004820 strncpy(pSMB->RequestFileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004821 }
4822
Steve French790fe572007-07-07 19:25:05 +00004823 if (ses->server) {
Steve French96daf2b2011-05-27 04:34:02 +00004824 if (ses->server->sec_mode &
Steve French1a4e15a2006-10-12 21:33:51 +00004825 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4826 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4827 }
4828
Steve French50c2f752007-07-13 00:33:32 +00004829 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004830
Linus Torvalds1da177e2005-04-16 15:20:36 -07004831 params = 2 /* level */ + name_len /*includes null */ ;
4832 pSMB->TotalDataCount = 0;
4833 pSMB->DataCount = 0;
4834 pSMB->DataOffset = 0;
4835 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004836 /* BB find exact max SMB PDU from sess structure BB */
4837 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004838 pSMB->MaxSetupCount = 0;
4839 pSMB->Reserved = 0;
4840 pSMB->Flags = 0;
4841 pSMB->Timeout = 0;
4842 pSMB->Reserved2 = 0;
4843 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004844 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004845 pSMB->SetupCount = 1;
4846 pSMB->Reserved3 = 0;
4847 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4848 byte_count = params + 3 /* pad */ ;
4849 pSMB->ParameterCount = cpu_to_le16(params);
4850 pSMB->TotalParameterCount = pSMB->ParameterCount;
4851 pSMB->MaxReferralLevel = cpu_to_le16(3);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004852 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004853 pSMB->ByteCount = cpu_to_le16(byte_count);
4854
4855 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4856 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4857 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004858 cFYI(1, "Send error in GetDFSRefer = %d", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004859 goto GetDFSRefExit;
4860 }
4861 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004862
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004863 /* BB Also check if enough total bytes returned? */
Jeff Layton820a8032011-05-04 08:05:26 -04004864 if (rc || get_bcc(&pSMBr->hdr) < 17) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004865 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004866 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004867 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004868
Joe Perchesb6b38f72010-04-21 03:50:45 +00004869 cFYI(1, "Decoding GetDFSRefer response BCC: %d Offset %d",
Jeff Layton820a8032011-05-04 08:05:26 -04004870 get_bcc(&pSMBr->hdr),
Joe Perchesb6b38f72010-04-21 03:50:45 +00004871 le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04004872
4873 /* parse returned result into more usable form */
Steve Frencha1fe78f2008-05-16 18:48:38 +00004874 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004875 target_nodes, nls_codepage, remap,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004876 search_name);
Igor Mammedovfec45852008-05-16 13:06:30 +04004877
Linus Torvalds1da177e2005-04-16 15:20:36 -07004878GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004879 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004880
4881 if (rc == -EAGAIN)
4882 goto getDFSRetry;
4883
4884 return rc;
4885}
4886
Steve French20962432005-09-21 22:05:57 -07004887/* Query File System Info such as free space to old servers such as Win 9x */
4888int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004889SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4890 struct kstatfs *FSData)
Steve French20962432005-09-21 22:05:57 -07004891{
4892/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4893 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4894 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4895 FILE_SYSTEM_ALLOC_INFO *response_data;
4896 int rc = 0;
4897 int bytes_returned = 0;
4898 __u16 params, byte_count;
4899
Joe Perchesb6b38f72010-04-21 03:50:45 +00004900 cFYI(1, "OldQFSInfo");
Steve French20962432005-09-21 22:05:57 -07004901oldQFSInfoRetry:
4902 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4903 (void **) &pSMBr);
4904 if (rc)
4905 return rc;
Steve French20962432005-09-21 22:05:57 -07004906
4907 params = 2; /* level */
4908 pSMB->TotalDataCount = 0;
4909 pSMB->MaxParameterCount = cpu_to_le16(2);
4910 pSMB->MaxDataCount = cpu_to_le16(1000);
4911 pSMB->MaxSetupCount = 0;
4912 pSMB->Reserved = 0;
4913 pSMB->Flags = 0;
4914 pSMB->Timeout = 0;
4915 pSMB->Reserved2 = 0;
4916 byte_count = params + 1 /* pad */ ;
4917 pSMB->TotalParameterCount = cpu_to_le16(params);
4918 pSMB->ParameterCount = pSMB->TotalParameterCount;
4919 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4920 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4921 pSMB->DataCount = 0;
4922 pSMB->DataOffset = 0;
4923 pSMB->SetupCount = 1;
4924 pSMB->Reserved3 = 0;
4925 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4926 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004927 inc_rfc1001_len(pSMB, byte_count);
Steve French20962432005-09-21 22:05:57 -07004928 pSMB->ByteCount = cpu_to_le16(byte_count);
4929
4930 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4931 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4932 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004933 cFYI(1, "Send error in QFSInfo = %d", rc);
Steve French20962432005-09-21 22:05:57 -07004934 } else { /* decode response */
4935 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4936
Jeff Layton820a8032011-05-04 08:05:26 -04004937 if (rc || get_bcc(&pSMBr->hdr) < 18)
Steve French20962432005-09-21 22:05:57 -07004938 rc = -EIO; /* bad smb */
4939 else {
4940 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004941 cFYI(1, "qfsinf resp BCC: %d Offset %d",
Jeff Layton820a8032011-05-04 08:05:26 -04004942 get_bcc(&pSMBr->hdr), data_offset);
Steve French20962432005-09-21 22:05:57 -07004943
Steve French50c2f752007-07-13 00:33:32 +00004944 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004945 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4946 FSData->f_bsize =
4947 le16_to_cpu(response_data->BytesPerSector) *
4948 le32_to_cpu(response_data->
4949 SectorsPerAllocationUnit);
4950 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004951 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004952 FSData->f_bfree = FSData->f_bavail =
4953 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004954 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
4955 (unsigned long long)FSData->f_blocks,
4956 (unsigned long long)FSData->f_bfree,
4957 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07004958 }
4959 }
4960 cifs_buf_release(pSMB);
4961
4962 if (rc == -EAGAIN)
4963 goto oldQFSInfoRetry;
4964
4965 return rc;
4966}
4967
Linus Torvalds1da177e2005-04-16 15:20:36 -07004968int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004969CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4970 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004971{
4972/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4973 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4974 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4975 FILE_SYSTEM_INFO *response_data;
4976 int rc = 0;
4977 int bytes_returned = 0;
4978 __u16 params, byte_count;
4979
Joe Perchesb6b38f72010-04-21 03:50:45 +00004980 cFYI(1, "In QFSInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004981QFSInfoRetry:
4982 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4983 (void **) &pSMBr);
4984 if (rc)
4985 return rc;
4986
4987 params = 2; /* level */
4988 pSMB->TotalDataCount = 0;
4989 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004990 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004991 pSMB->MaxSetupCount = 0;
4992 pSMB->Reserved = 0;
4993 pSMB->Flags = 0;
4994 pSMB->Timeout = 0;
4995 pSMB->Reserved2 = 0;
4996 byte_count = params + 1 /* pad */ ;
4997 pSMB->TotalParameterCount = cpu_to_le16(params);
4998 pSMB->ParameterCount = pSMB->TotalParameterCount;
4999 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005000 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005001 pSMB->DataCount = 0;
5002 pSMB->DataOffset = 0;
5003 pSMB->SetupCount = 1;
5004 pSMB->Reserved3 = 0;
5005 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5006 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005007 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005008 pSMB->ByteCount = cpu_to_le16(byte_count);
5009
5010 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5011 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5012 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005013 cFYI(1, "Send error in QFSInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005014 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00005015 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005016
Jeff Layton820a8032011-05-04 08:05:26 -04005017 if (rc || get_bcc(&pSMBr->hdr) < 24)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005018 rc = -EIO; /* bad smb */
5019 else {
5020 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005021
5022 response_data =
5023 (FILE_SYSTEM_INFO
5024 *) (((char *) &pSMBr->hdr.Protocol) +
5025 data_offset);
5026 FSData->f_bsize =
5027 le32_to_cpu(response_data->BytesPerSector) *
5028 le32_to_cpu(response_data->
5029 SectorsPerAllocationUnit);
5030 FSData->f_blocks =
5031 le64_to_cpu(response_data->TotalAllocationUnits);
5032 FSData->f_bfree = FSData->f_bavail =
5033 le64_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesb6b38f72010-04-21 03:50:45 +00005034 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
5035 (unsigned long long)FSData->f_blocks,
5036 (unsigned long long)FSData->f_bfree,
5037 FSData->f_bsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005038 }
5039 }
5040 cifs_buf_release(pSMB);
5041
5042 if (rc == -EAGAIN)
5043 goto QFSInfoRetry;
5044
5045 return rc;
5046}
5047
5048int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005049CIFSSMBQFSAttributeInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005050{
5051/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
5052 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5053 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5054 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
5055 int rc = 0;
5056 int bytes_returned = 0;
5057 __u16 params, byte_count;
5058
Joe Perchesb6b38f72010-04-21 03:50:45 +00005059 cFYI(1, "In QFSAttributeInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005060QFSAttributeRetry:
5061 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5062 (void **) &pSMBr);
5063 if (rc)
5064 return rc;
5065
5066 params = 2; /* level */
5067 pSMB->TotalDataCount = 0;
5068 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005069 /* BB find exact max SMB PDU from sess structure BB */
5070 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005071 pSMB->MaxSetupCount = 0;
5072 pSMB->Reserved = 0;
5073 pSMB->Flags = 0;
5074 pSMB->Timeout = 0;
5075 pSMB->Reserved2 = 0;
5076 byte_count = params + 1 /* pad */ ;
5077 pSMB->TotalParameterCount = cpu_to_le16(params);
5078 pSMB->ParameterCount = pSMB->TotalParameterCount;
5079 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005080 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005081 pSMB->DataCount = 0;
5082 pSMB->DataOffset = 0;
5083 pSMB->SetupCount = 1;
5084 pSMB->Reserved3 = 0;
5085 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5086 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005087 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005088 pSMB->ByteCount = cpu_to_le16(byte_count);
5089
5090 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5091 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5092 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005093 cERROR(1, "Send error in QFSAttributeInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005094 } else { /* decode response */
5095 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5096
Jeff Layton820a8032011-05-04 08:05:26 -04005097 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Steve French50c2f752007-07-13 00:33:32 +00005098 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005099 rc = -EIO; /* bad smb */
5100 } else {
5101 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5102 response_data =
5103 (FILE_SYSTEM_ATTRIBUTE_INFO
5104 *) (((char *) &pSMBr->hdr.Protocol) +
5105 data_offset);
5106 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005107 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005108 }
5109 }
5110 cifs_buf_release(pSMB);
5111
5112 if (rc == -EAGAIN)
5113 goto QFSAttributeRetry;
5114
5115 return rc;
5116}
5117
5118int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005119CIFSSMBQFSDeviceInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005120{
5121/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
5122 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5123 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5124 FILE_SYSTEM_DEVICE_INFO *response_data;
5125 int rc = 0;
5126 int bytes_returned = 0;
5127 __u16 params, byte_count;
5128
Joe Perchesb6b38f72010-04-21 03:50:45 +00005129 cFYI(1, "In QFSDeviceInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005130QFSDeviceRetry:
5131 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5132 (void **) &pSMBr);
5133 if (rc)
5134 return rc;
5135
5136 params = 2; /* level */
5137 pSMB->TotalDataCount = 0;
5138 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005139 /* BB find exact max SMB PDU from sess structure BB */
5140 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005141 pSMB->MaxSetupCount = 0;
5142 pSMB->Reserved = 0;
5143 pSMB->Flags = 0;
5144 pSMB->Timeout = 0;
5145 pSMB->Reserved2 = 0;
5146 byte_count = params + 1 /* pad */ ;
5147 pSMB->TotalParameterCount = cpu_to_le16(params);
5148 pSMB->ParameterCount = pSMB->TotalParameterCount;
5149 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005150 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005151
5152 pSMB->DataCount = 0;
5153 pSMB->DataOffset = 0;
5154 pSMB->SetupCount = 1;
5155 pSMB->Reserved3 = 0;
5156 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5157 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005158 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005159 pSMB->ByteCount = cpu_to_le16(byte_count);
5160
5161 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5162 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5163 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005164 cFYI(1, "Send error in QFSDeviceInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005165 } else { /* decode response */
5166 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5167
Jeff Layton820a8032011-05-04 08:05:26 -04005168 if (rc || get_bcc(&pSMBr->hdr) <
5169 sizeof(FILE_SYSTEM_DEVICE_INFO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005170 rc = -EIO; /* bad smb */
5171 else {
5172 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5173 response_data =
Steve French737b7582005-04-28 22:41:06 -07005174 (FILE_SYSTEM_DEVICE_INFO *)
5175 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07005176 data_offset);
5177 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005178 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005179 }
5180 }
5181 cifs_buf_release(pSMB);
5182
5183 if (rc == -EAGAIN)
5184 goto QFSDeviceRetry;
5185
5186 return rc;
5187}
5188
5189int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005190CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005191{
5192/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
5193 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5194 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5195 FILE_SYSTEM_UNIX_INFO *response_data;
5196 int rc = 0;
5197 int bytes_returned = 0;
5198 __u16 params, byte_count;
5199
Joe Perchesb6b38f72010-04-21 03:50:45 +00005200 cFYI(1, "In QFSUnixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005201QFSUnixRetry:
Jeff Laytonf5695992010-09-29 15:27:08 -04005202 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5203 (void **) &pSMB, (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005204 if (rc)
5205 return rc;
5206
5207 params = 2; /* level */
5208 pSMB->TotalDataCount = 0;
5209 pSMB->DataCount = 0;
5210 pSMB->DataOffset = 0;
5211 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005212 /* BB find exact max SMB PDU from sess structure BB */
5213 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005214 pSMB->MaxSetupCount = 0;
5215 pSMB->Reserved = 0;
5216 pSMB->Flags = 0;
5217 pSMB->Timeout = 0;
5218 pSMB->Reserved2 = 0;
5219 byte_count = params + 1 /* pad */ ;
5220 pSMB->ParameterCount = cpu_to_le16(params);
5221 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005222 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5223 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005224 pSMB->SetupCount = 1;
5225 pSMB->Reserved3 = 0;
5226 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5227 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005228 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005229 pSMB->ByteCount = cpu_to_le16(byte_count);
5230
5231 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5232 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5233 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005234 cERROR(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005235 } else { /* decode response */
5236 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5237
Jeff Layton820a8032011-05-04 08:05:26 -04005238 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005239 rc = -EIO; /* bad smb */
5240 } else {
5241 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5242 response_data =
5243 (FILE_SYSTEM_UNIX_INFO
5244 *) (((char *) &pSMBr->hdr.Protocol) +
5245 data_offset);
5246 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005247 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005248 }
5249 }
5250 cifs_buf_release(pSMB);
5251
5252 if (rc == -EAGAIN)
5253 goto QFSUnixRetry;
5254
5255
5256 return rc;
5257}
5258
Jeremy Allisonac670552005-06-22 17:26:35 -07005259int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005260CIFSSMBSetFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07005261{
5262/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
5263 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
5264 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
5265 int rc = 0;
5266 int bytes_returned = 0;
5267 __u16 params, param_offset, offset, byte_count;
5268
Joe Perchesb6b38f72010-04-21 03:50:45 +00005269 cFYI(1, "In SETFSUnixInfo");
Jeremy Allisonac670552005-06-22 17:26:35 -07005270SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00005271 /* BB switch to small buf init to save memory */
Jeff Laytonf5695992010-09-29 15:27:08 -04005272 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5273 (void **) &pSMB, (void **) &pSMBr);
Jeremy Allisonac670552005-06-22 17:26:35 -07005274 if (rc)
5275 return rc;
5276
5277 params = 4; /* 2 bytes zero followed by info level. */
5278 pSMB->MaxSetupCount = 0;
5279 pSMB->Reserved = 0;
5280 pSMB->Flags = 0;
5281 pSMB->Timeout = 0;
5282 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00005283 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
5284 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07005285 offset = param_offset + params;
5286
5287 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00005288 /* BB find exact max SMB PDU from sess structure BB */
5289 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07005290 pSMB->SetupCount = 1;
5291 pSMB->Reserved3 = 0;
5292 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
5293 byte_count = 1 /* pad */ + params + 12;
5294
5295 pSMB->DataCount = cpu_to_le16(12);
5296 pSMB->ParameterCount = cpu_to_le16(params);
5297 pSMB->TotalDataCount = pSMB->DataCount;
5298 pSMB->TotalParameterCount = pSMB->ParameterCount;
5299 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5300 pSMB->DataOffset = cpu_to_le16(offset);
5301
5302 /* Params. */
5303 pSMB->FileNum = 0;
5304 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
5305
5306 /* Data. */
5307 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
5308 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
5309 pSMB->ClientUnixCap = cpu_to_le64(cap);
5310
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005311 inc_rfc1001_len(pSMB, byte_count);
Jeremy Allisonac670552005-06-22 17:26:35 -07005312 pSMB->ByteCount = cpu_to_le16(byte_count);
5313
5314 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5315 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5316 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005317 cERROR(1, "Send error in SETFSUnixInfo = %d", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07005318 } else { /* decode response */
5319 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00005320 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07005321 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07005322 }
5323 cifs_buf_release(pSMB);
5324
5325 if (rc == -EAGAIN)
5326 goto SETFSUnixRetry;
5327
5328 return rc;
5329}
5330
5331
Linus Torvalds1da177e2005-04-16 15:20:36 -07005332
5333int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005334CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon,
Steve French737b7582005-04-28 22:41:06 -07005335 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005336{
5337/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
5338 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5339 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5340 FILE_SYSTEM_POSIX_INFO *response_data;
5341 int rc = 0;
5342 int bytes_returned = 0;
5343 __u16 params, byte_count;
5344
Joe Perchesb6b38f72010-04-21 03:50:45 +00005345 cFYI(1, "In QFSPosixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005346QFSPosixRetry:
5347 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5348 (void **) &pSMBr);
5349 if (rc)
5350 return rc;
5351
5352 params = 2; /* level */
5353 pSMB->TotalDataCount = 0;
5354 pSMB->DataCount = 0;
5355 pSMB->DataOffset = 0;
5356 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005357 /* BB find exact max SMB PDU from sess structure BB */
5358 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005359 pSMB->MaxSetupCount = 0;
5360 pSMB->Reserved = 0;
5361 pSMB->Flags = 0;
5362 pSMB->Timeout = 0;
5363 pSMB->Reserved2 = 0;
5364 byte_count = params + 1 /* pad */ ;
5365 pSMB->ParameterCount = cpu_to_le16(params);
5366 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005367 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5368 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005369 pSMB->SetupCount = 1;
5370 pSMB->Reserved3 = 0;
5371 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5372 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005373 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005374 pSMB->ByteCount = cpu_to_le16(byte_count);
5375
5376 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5377 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5378 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005379 cFYI(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005380 } else { /* decode response */
5381 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5382
Jeff Layton820a8032011-05-04 08:05:26 -04005383 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005384 rc = -EIO; /* bad smb */
5385 } else {
5386 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5387 response_data =
5388 (FILE_SYSTEM_POSIX_INFO
5389 *) (((char *) &pSMBr->hdr.Protocol) +
5390 data_offset);
5391 FSData->f_bsize =
5392 le32_to_cpu(response_data->BlockSize);
5393 FSData->f_blocks =
5394 le64_to_cpu(response_data->TotalBlocks);
5395 FSData->f_bfree =
5396 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00005397 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005398 FSData->f_bavail = FSData->f_bfree;
5399 } else {
5400 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00005401 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005402 }
Steve French790fe572007-07-07 19:25:05 +00005403 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005404 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00005405 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00005406 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005407 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00005408 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005409 }
5410 }
5411 cifs_buf_release(pSMB);
5412
5413 if (rc == -EAGAIN)
5414 goto QFSPosixRetry;
5415
5416 return rc;
5417}
5418
5419
Steve French50c2f752007-07-13 00:33:32 +00005420/* We can not use write of zero bytes trick to
5421 set file size due to need for large file support. Also note that
5422 this SetPathInfo is preferred to SetFileInfo based method in next
Linus Torvalds1da177e2005-04-16 15:20:36 -07005423 routine which is only needed to work around a sharing violation bug
5424 in Samba which this routine can run into */
5425
5426int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005427CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
5428 const char *fileName, __u64 size, bool SetAllocation,
Steve French737b7582005-04-28 22:41:06 -07005429 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005430{
5431 struct smb_com_transaction2_spi_req *pSMB = NULL;
5432 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5433 struct file_end_of_file_info *parm_data;
5434 int name_len;
5435 int rc = 0;
5436 int bytes_returned = 0;
5437 __u16 params, byte_count, data_count, param_offset, offset;
5438
Joe Perchesb6b38f72010-04-21 03:50:45 +00005439 cFYI(1, "In SetEOF");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005440SetEOFRetry:
5441 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5442 (void **) &pSMBr);
5443 if (rc)
5444 return rc;
5445
5446 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5447 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005448 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5449 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005450 name_len++; /* trailing null */
5451 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005452 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005453 name_len = strnlen(fileName, PATH_MAX);
5454 name_len++; /* trailing null */
5455 strncpy(pSMB->FileName, fileName, name_len);
5456 }
5457 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005458 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005459 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07005460 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005461 pSMB->MaxSetupCount = 0;
5462 pSMB->Reserved = 0;
5463 pSMB->Flags = 0;
5464 pSMB->Timeout = 0;
5465 pSMB->Reserved2 = 0;
5466 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005467 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005468 offset = param_offset + params;
Steve French790fe572007-07-07 19:25:05 +00005469 if (SetAllocation) {
Steve French50c2f752007-07-13 00:33:32 +00005470 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5471 pSMB->InformationLevel =
5472 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5473 else
5474 pSMB->InformationLevel =
5475 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5476 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005477 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5478 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005479 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005480 else
5481 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005482 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005483 }
5484
5485 parm_data =
5486 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
5487 offset);
5488 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5489 pSMB->DataOffset = cpu_to_le16(offset);
5490 pSMB->SetupCount = 1;
5491 pSMB->Reserved3 = 0;
5492 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5493 byte_count = 3 /* pad */ + params + data_count;
5494 pSMB->DataCount = cpu_to_le16(data_count);
5495 pSMB->TotalDataCount = pSMB->DataCount;
5496 pSMB->ParameterCount = cpu_to_le16(params);
5497 pSMB->TotalParameterCount = pSMB->ParameterCount;
5498 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005499 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005500 parm_data->FileSize = cpu_to_le64(size);
5501 pSMB->ByteCount = cpu_to_le16(byte_count);
5502 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5503 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005504 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005505 cFYI(1, "SetPathInfo (file size) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005506
5507 cifs_buf_release(pSMB);
5508
5509 if (rc == -EAGAIN)
5510 goto SetEOFRetry;
5511
5512 return rc;
5513}
5514
5515int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005516CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon, __u64 size,
Steve French4b18f2a2008-04-29 00:06:05 +00005517 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005518{
5519 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005520 struct file_end_of_file_info *parm_data;
5521 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005522 __u16 params, param_offset, offset, byte_count, count;
5523
Joe Perchesb6b38f72010-04-21 03:50:45 +00005524 cFYI(1, "SetFileSize (via SetFileInfo) %lld",
5525 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07005526 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5527
Linus Torvalds1da177e2005-04-16 15:20:36 -07005528 if (rc)
5529 return rc;
5530
5531 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5532 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005533
Linus Torvalds1da177e2005-04-16 15:20:36 -07005534 params = 6;
5535 pSMB->MaxSetupCount = 0;
5536 pSMB->Reserved = 0;
5537 pSMB->Flags = 0;
5538 pSMB->Timeout = 0;
5539 pSMB->Reserved2 = 0;
5540 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5541 offset = param_offset + params;
5542
Linus Torvalds1da177e2005-04-16 15:20:36 -07005543 count = sizeof(struct file_end_of_file_info);
5544 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005545 /* BB find exact max SMB PDU from sess structure BB */
5546 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005547 pSMB->SetupCount = 1;
5548 pSMB->Reserved3 = 0;
5549 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5550 byte_count = 3 /* pad */ + params + count;
5551 pSMB->DataCount = cpu_to_le16(count);
5552 pSMB->ParameterCount = cpu_to_le16(params);
5553 pSMB->TotalDataCount = pSMB->DataCount;
5554 pSMB->TotalParameterCount = pSMB->ParameterCount;
5555 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5556 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00005557 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
5558 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005559 pSMB->DataOffset = cpu_to_le16(offset);
5560 parm_data->FileSize = cpu_to_le64(size);
5561 pSMB->Fid = fid;
Steve French790fe572007-07-07 19:25:05 +00005562 if (SetAllocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005563 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5564 pSMB->InformationLevel =
5565 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5566 else
5567 pSMB->InformationLevel =
5568 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00005569 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005570 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5571 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005572 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005573 else
5574 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005575 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005576 }
5577 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005578 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005579 pSMB->ByteCount = cpu_to_le16(byte_count);
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005580 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005581 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005582 cFYI(1, "Send error in SetFileInfo (SetFileSize) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005583 }
5584
Steve French50c2f752007-07-13 00:33:32 +00005585 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005586 since file handle passed in no longer valid */
5587
5588 return rc;
5589}
5590
Steve French50c2f752007-07-13 00:33:32 +00005591/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07005592 an open handle, rather than by pathname - this is awkward due to
5593 potential access conflicts on the open, but it is unavoidable for these
5594 old servers since the only other choice is to go from 100 nanosecond DCE
5595 time and resort to the original setpathinfo level which takes the ancient
5596 DOS time format with 2 second granularity */
5597int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005598CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005599 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005600{
5601 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005602 char *data_offset;
5603 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005604 __u16 params, param_offset, offset, byte_count, count;
5605
Joe Perchesb6b38f72010-04-21 03:50:45 +00005606 cFYI(1, "Set Times (via SetFileInfo)");
Steve Frenchcd634992005-04-28 22:41:10 -07005607 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5608
Linus Torvalds1da177e2005-04-16 15:20:36 -07005609 if (rc)
5610 return rc;
5611
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005612 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5613 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005614
Linus Torvalds1da177e2005-04-16 15:20:36 -07005615 params = 6;
5616 pSMB->MaxSetupCount = 0;
5617 pSMB->Reserved = 0;
5618 pSMB->Flags = 0;
5619 pSMB->Timeout = 0;
5620 pSMB->Reserved2 = 0;
5621 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5622 offset = param_offset + params;
5623
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005624 data_offset = (char *)pSMB +
5625 offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005626
Steve French26f57362007-08-30 22:09:15 +00005627 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005628 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005629 /* BB find max SMB PDU from sess */
5630 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005631 pSMB->SetupCount = 1;
5632 pSMB->Reserved3 = 0;
5633 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5634 byte_count = 3 /* pad */ + params + count;
5635 pSMB->DataCount = cpu_to_le16(count);
5636 pSMB->ParameterCount = cpu_to_le16(params);
5637 pSMB->TotalDataCount = pSMB->DataCount;
5638 pSMB->TotalParameterCount = pSMB->ParameterCount;
5639 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5640 pSMB->DataOffset = cpu_to_le16(offset);
5641 pSMB->Fid = fid;
5642 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5643 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5644 else
5645 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5646 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005647 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005648 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005649 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005650 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005651 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005652 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005653
Steve French50c2f752007-07-13 00:33:32 +00005654 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005655 since file handle passed in no longer valid */
5656
5657 return rc;
5658}
5659
Jeff Layton6d22f092008-09-23 11:48:35 -04005660int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005661CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6d22f092008-09-23 11:48:35 -04005662 bool delete_file, __u16 fid, __u32 pid_of_opener)
5663{
5664 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5665 char *data_offset;
5666 int rc = 0;
5667 __u16 params, param_offset, offset, byte_count, count;
5668
Joe Perchesb6b38f72010-04-21 03:50:45 +00005669 cFYI(1, "Set File Disposition (via SetFileInfo)");
Jeff Layton6d22f092008-09-23 11:48:35 -04005670 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5671
5672 if (rc)
5673 return rc;
5674
5675 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5676 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5677
5678 params = 6;
5679 pSMB->MaxSetupCount = 0;
5680 pSMB->Reserved = 0;
5681 pSMB->Flags = 0;
5682 pSMB->Timeout = 0;
5683 pSMB->Reserved2 = 0;
5684 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5685 offset = param_offset + params;
5686
5687 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5688
5689 count = 1;
5690 pSMB->MaxParameterCount = cpu_to_le16(2);
5691 /* BB find max SMB PDU from sess */
5692 pSMB->MaxDataCount = cpu_to_le16(1000);
5693 pSMB->SetupCount = 1;
5694 pSMB->Reserved3 = 0;
5695 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5696 byte_count = 3 /* pad */ + params + count;
5697 pSMB->DataCount = cpu_to_le16(count);
5698 pSMB->ParameterCount = cpu_to_le16(params);
5699 pSMB->TotalDataCount = pSMB->DataCount;
5700 pSMB->TotalParameterCount = pSMB->ParameterCount;
5701 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5702 pSMB->DataOffset = cpu_to_le16(offset);
5703 pSMB->Fid = fid;
5704 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5705 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005706 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton6d22f092008-09-23 11:48:35 -04005707 pSMB->ByteCount = cpu_to_le16(byte_count);
5708 *data_offset = delete_file ? 1 : 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005709 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Jeff Layton6d22f092008-09-23 11:48:35 -04005710 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005711 cFYI(1, "Send error in SetFileDisposition = %d", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005712
5713 return rc;
5714}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005715
5716int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005717CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6fc000e2008-08-02 07:26:12 -04005718 const char *fileName, const FILE_BASIC_INFO *data,
5719 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005720{
5721 TRANSACTION2_SPI_REQ *pSMB = NULL;
5722 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5723 int name_len;
5724 int rc = 0;
5725 int bytes_returned = 0;
5726 char *data_offset;
5727 __u16 params, param_offset, offset, byte_count, count;
5728
Joe Perchesb6b38f72010-04-21 03:50:45 +00005729 cFYI(1, "In SetTimes");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005730
5731SetTimesRetry:
5732 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5733 (void **) &pSMBr);
5734 if (rc)
5735 return rc;
5736
5737 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5738 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005739 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5740 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005741 name_len++; /* trailing null */
5742 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005743 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005744 name_len = strnlen(fileName, PATH_MAX);
5745 name_len++; /* trailing null */
5746 strncpy(pSMB->FileName, fileName, name_len);
5747 }
5748
5749 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005750 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005751 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005752 /* BB find max SMB PDU from sess structure BB */
5753 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005754 pSMB->MaxSetupCount = 0;
5755 pSMB->Reserved = 0;
5756 pSMB->Flags = 0;
5757 pSMB->Timeout = 0;
5758 pSMB->Reserved2 = 0;
5759 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005760 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005761 offset = param_offset + params;
5762 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5763 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5764 pSMB->DataOffset = cpu_to_le16(offset);
5765 pSMB->SetupCount = 1;
5766 pSMB->Reserved3 = 0;
5767 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5768 byte_count = 3 /* pad */ + params + count;
5769
5770 pSMB->DataCount = cpu_to_le16(count);
5771 pSMB->ParameterCount = cpu_to_le16(params);
5772 pSMB->TotalDataCount = pSMB->DataCount;
5773 pSMB->TotalParameterCount = pSMB->ParameterCount;
5774 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5775 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5776 else
5777 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5778 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005779 inc_rfc1001_len(pSMB, byte_count);
Steve French26f57362007-08-30 22:09:15 +00005780 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005781 pSMB->ByteCount = cpu_to_le16(byte_count);
5782 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5783 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005784 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005785 cFYI(1, "SetPathInfo (times) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005786
5787 cifs_buf_release(pSMB);
5788
5789 if (rc == -EAGAIN)
5790 goto SetTimesRetry;
5791
5792 return rc;
5793}
5794
5795/* Can not be used to set time stamps yet (due to old DOS time format) */
5796/* Can be used to set attributes */
5797#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5798 handling it anyway and NT4 was what we thought it would be needed for
5799 Do not delete it until we prove whether needed for Win9x though */
5800int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005801CIFSSMBSetAttrLegacy(unsigned int xid, struct cifs_tcon *tcon, char *fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005802 __u16 dos_attrs, const struct nls_table *nls_codepage)
5803{
5804 SETATTR_REQ *pSMB = NULL;
5805 SETATTR_RSP *pSMBr = NULL;
5806 int rc = 0;
5807 int bytes_returned;
5808 int name_len;
5809
Joe Perchesb6b38f72010-04-21 03:50:45 +00005810 cFYI(1, "In SetAttrLegacy");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005811
5812SetAttrLgcyRetry:
5813 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5814 (void **) &pSMBr);
5815 if (rc)
5816 return rc;
5817
5818 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5819 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005820 ConvertToUTF16((__le16 *) pSMB->fileName, fileName,
5821 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005822 name_len++; /* trailing null */
5823 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005824 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005825 name_len = strnlen(fileName, PATH_MAX);
5826 name_len++; /* trailing null */
5827 strncpy(pSMB->fileName, fileName, name_len);
5828 }
5829 pSMB->attr = cpu_to_le16(dos_attrs);
5830 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005831 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005832 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5833 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5834 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005835 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005836 cFYI(1, "Error in LegacySetAttr = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005837
5838 cifs_buf_release(pSMB);
5839
5840 if (rc == -EAGAIN)
5841 goto SetAttrLgcyRetry;
5842
5843 return rc;
5844}
5845#endif /* temporarily unneeded SetAttr legacy function */
5846
Jeff Layton654cf142009-07-09 20:02:49 -04005847static void
5848cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5849 const struct cifs_unix_set_info_args *args)
5850{
5851 u64 mode = args->mode;
5852
5853 /*
5854 * Samba server ignores set of file size to zero due to bugs in some
5855 * older clients, but we should be precise - we use SetFileSize to
5856 * set file size and do not want to truncate file size to zero
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005857 * accidentally as happened on one Samba server beta by putting
Jeff Layton654cf142009-07-09 20:02:49 -04005858 * zero instead of -1 here
5859 */
5860 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5861 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5862 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5863 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5864 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5865 data_offset->Uid = cpu_to_le64(args->uid);
5866 data_offset->Gid = cpu_to_le64(args->gid);
5867 /* better to leave device as zero when it is */
5868 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5869 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5870 data_offset->Permissions = cpu_to_le64(mode);
5871
5872 if (S_ISREG(mode))
5873 data_offset->Type = cpu_to_le32(UNIX_FILE);
5874 else if (S_ISDIR(mode))
5875 data_offset->Type = cpu_to_le32(UNIX_DIR);
5876 else if (S_ISLNK(mode))
5877 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5878 else if (S_ISCHR(mode))
5879 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5880 else if (S_ISBLK(mode))
5881 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5882 else if (S_ISFIFO(mode))
5883 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5884 else if (S_ISSOCK(mode))
5885 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5886}
5887
Linus Torvalds1da177e2005-04-16 15:20:36 -07005888int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005889CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005890 const struct cifs_unix_set_info_args *args,
5891 u16 fid, u32 pid_of_opener)
5892{
5893 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005894 char *data_offset;
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005895 int rc = 0;
5896 u16 params, param_offset, offset, byte_count, count;
5897
Joe Perchesb6b38f72010-04-21 03:50:45 +00005898 cFYI(1, "Set Unix Info (via SetFileInfo)");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005899 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5900
5901 if (rc)
5902 return rc;
5903
5904 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5905 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5906
5907 params = 6;
5908 pSMB->MaxSetupCount = 0;
5909 pSMB->Reserved = 0;
5910 pSMB->Flags = 0;
5911 pSMB->Timeout = 0;
5912 pSMB->Reserved2 = 0;
5913 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5914 offset = param_offset + params;
5915
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005916 data_offset = (char *)pSMB +
5917 offsetof(struct smb_hdr, Protocol) + offset;
5918
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005919 count = sizeof(FILE_UNIX_BASIC_INFO);
5920
5921 pSMB->MaxParameterCount = cpu_to_le16(2);
5922 /* BB find max SMB PDU from sess */
5923 pSMB->MaxDataCount = cpu_to_le16(1000);
5924 pSMB->SetupCount = 1;
5925 pSMB->Reserved3 = 0;
5926 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5927 byte_count = 3 /* pad */ + params + count;
5928 pSMB->DataCount = cpu_to_le16(count);
5929 pSMB->ParameterCount = cpu_to_le16(params);
5930 pSMB->TotalDataCount = pSMB->DataCount;
5931 pSMB->TotalParameterCount = pSMB->ParameterCount;
5932 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5933 pSMB->DataOffset = cpu_to_le16(offset);
5934 pSMB->Fid = fid;
5935 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5936 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005937 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005938 pSMB->ByteCount = cpu_to_le16(byte_count);
5939
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005940 cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005941
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005942 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005943 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005944 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005945
5946 /* Note: On -EAGAIN error only caller can retry on handle based calls
5947 since file handle passed in no longer valid */
5948
5949 return rc;
5950}
5951
5952int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005953CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005954 const char *file_name,
Jeff Layton01ea95e2009-07-09 20:02:49 -04005955 const struct cifs_unix_set_info_args *args,
5956 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005957{
5958 TRANSACTION2_SPI_REQ *pSMB = NULL;
5959 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5960 int name_len;
5961 int rc = 0;
5962 int bytes_returned = 0;
5963 FILE_UNIX_BASIC_INFO *data_offset;
5964 __u16 params, param_offset, offset, count, byte_count;
5965
Joe Perchesb6b38f72010-04-21 03:50:45 +00005966 cFYI(1, "In SetUID/GID/Mode");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005967setPermsRetry:
5968 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5969 (void **) &pSMBr);
5970 if (rc)
5971 return rc;
5972
5973 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5974 name_len =
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005975 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06005976 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005977 name_len++; /* trailing null */
5978 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005979 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005980 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005981 name_len++; /* trailing null */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005982 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005983 }
5984
5985 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005986 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005987 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005988 /* BB find max SMB PDU from sess structure BB */
5989 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005990 pSMB->MaxSetupCount = 0;
5991 pSMB->Reserved = 0;
5992 pSMB->Flags = 0;
5993 pSMB->Timeout = 0;
5994 pSMB->Reserved2 = 0;
5995 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005996 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005997 offset = param_offset + params;
5998 data_offset =
5999 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
6000 offset);
6001 memset(data_offset, 0, count);
6002 pSMB->DataOffset = cpu_to_le16(offset);
6003 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6004 pSMB->SetupCount = 1;
6005 pSMB->Reserved3 = 0;
6006 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6007 byte_count = 3 /* pad */ + params + count;
6008 pSMB->ParameterCount = cpu_to_le16(params);
6009 pSMB->DataCount = cpu_to_le16(count);
6010 pSMB->TotalParameterCount = pSMB->ParameterCount;
6011 pSMB->TotalDataCount = pSMB->DataCount;
6012 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6013 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006014 inc_rfc1001_len(pSMB, byte_count);
Steve French50c2f752007-07-13 00:33:32 +00006015
Jeff Layton654cf142009-07-09 20:02:49 -04006016 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006017
6018 pSMB->ByteCount = cpu_to_le16(byte_count);
6019 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6020 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006021 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00006022 cFYI(1, "SetPathInfo (perms) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006023
Steve French0d817bc2008-05-22 02:02:03 +00006024 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006025 if (rc == -EAGAIN)
6026 goto setPermsRetry;
6027 return rc;
6028}
6029
Linus Torvalds1da177e2005-04-16 15:20:36 -07006030#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05006031/*
6032 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
6033 * function used by listxattr and getxattr type calls. When ea_name is set,
6034 * it looks for that attribute name and stuffs that value into the EAData
6035 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
6036 * buffer. In both cases, the return value is either the length of the
6037 * resulting data or a negative error code. If EAData is a NULL pointer then
6038 * the data isn't copied to it, but the length is returned.
6039 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006040ssize_t
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006041CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05006042 const unsigned char *searchName, const unsigned char *ea_name,
6043 char *EAData, size_t buf_size,
6044 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006045{
6046 /* BB assumes one setup word */
6047 TRANSACTION2_QPI_REQ *pSMB = NULL;
6048 TRANSACTION2_QPI_RSP *pSMBr = NULL;
6049 int rc = 0;
6050 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05006051 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006052 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00006053 struct fea *temp_fea;
6054 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006055 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006056 __u16 params, byte_count, data_offset;
Jeff Layton5980fc92011-07-28 12:48:26 -04006057 unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006058
Joe Perchesb6b38f72010-04-21 03:50:45 +00006059 cFYI(1, "In Query All EAs path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006060QAllEAsRetry:
6061 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6062 (void **) &pSMBr);
6063 if (rc)
6064 return rc;
6065
6066 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05006067 list_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006068 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
6069 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05006070 list_len++; /* trailing null */
6071 list_len *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006072 } else { /* BB improve the check for buffer overruns BB */
Jeff Layton6e462b92010-02-10 16:18:26 -05006073 list_len = strnlen(searchName, PATH_MAX);
6074 list_len++; /* trailing null */
6075 strncpy(pSMB->FileName, searchName, list_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006076 }
6077
Jeff Layton6e462b92010-02-10 16:18:26 -05006078 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006079 pSMB->TotalDataCount = 0;
6080 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006081 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05006082 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006083 pSMB->MaxSetupCount = 0;
6084 pSMB->Reserved = 0;
6085 pSMB->Flags = 0;
6086 pSMB->Timeout = 0;
6087 pSMB->Reserved2 = 0;
6088 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00006089 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006090 pSMB->DataCount = 0;
6091 pSMB->DataOffset = 0;
6092 pSMB->SetupCount = 1;
6093 pSMB->Reserved3 = 0;
6094 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
6095 byte_count = params + 1 /* pad */ ;
6096 pSMB->TotalParameterCount = cpu_to_le16(params);
6097 pSMB->ParameterCount = pSMB->TotalParameterCount;
6098 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
6099 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006100 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006101 pSMB->ByteCount = cpu_to_le16(byte_count);
6102
6103 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6104 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6105 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006106 cFYI(1, "Send error in QueryAllEAs = %d", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05006107 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006108 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006109
6110
6111 /* BB also check enough total bytes returned */
6112 /* BB we need to improve the validity checking
6113 of these trans2 responses */
6114
6115 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Jeff Layton820a8032011-05-04 08:05:26 -04006116 if (rc || get_bcc(&pSMBr->hdr) < 4) {
Jeff Laytonf0d38682010-02-10 16:18:26 -05006117 rc = -EIO; /* bad smb */
6118 goto QAllEAsOut;
6119 }
6120
6121 /* check that length of list is not more than bcc */
6122 /* check that each entry does not go beyond length
6123 of list */
6124 /* check that each element of each entry does not
6125 go beyond end of list */
6126 /* validate_trans2_offsets() */
6127 /* BB check if start of smb + data_offset > &bcc+ bcc */
6128
6129 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
6130 ea_response_data = (struct fealist *)
6131 (((char *) &pSMBr->hdr.Protocol) + data_offset);
6132
Jeff Layton6e462b92010-02-10 16:18:26 -05006133 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesb6b38f72010-04-21 03:50:45 +00006134 cFYI(1, "ea length %d", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05006135 if (list_len <= 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006136 cFYI(1, "empty EA list returned from server");
Jeff Laytonf0d38682010-02-10 16:18:26 -05006137 goto QAllEAsOut;
6138 }
6139
Jeff Layton0cd126b2010-02-10 16:18:26 -05006140 /* make sure list_len doesn't go past end of SMB */
Jeff Layton690c5222011-01-20 13:36:51 -05006141 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
Jeff Layton0cd126b2010-02-10 16:18:26 -05006142 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006143 cFYI(1, "EA list appears to go beyond SMB");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006144 rc = -EIO;
6145 goto QAllEAsOut;
6146 }
6147
Jeff Laytonf0d38682010-02-10 16:18:26 -05006148 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05006149 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006150 temp_fea = ea_response_data->list;
6151 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05006152 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00006153 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006154 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006155
Jeff Layton6e462b92010-02-10 16:18:26 -05006156 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006157 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006158 /* make sure we can read name_len and value_len */
6159 if (list_len < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006160 cFYI(1, "EA entry goes beyond length of list");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006161 rc = -EIO;
6162 goto QAllEAsOut;
6163 }
6164
6165 name_len = temp_fea->name_len;
6166 value_len = le16_to_cpu(temp_fea->value_len);
6167 list_len -= name_len + 1 + value_len;
6168 if (list_len < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006169 cFYI(1, "EA entry goes beyond length of list");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006170 rc = -EIO;
6171 goto QAllEAsOut;
6172 }
6173
Jeff Layton31c05192010-02-10 16:18:26 -05006174 if (ea_name) {
Jeff Layton91d065c2011-07-26 18:23:47 -04006175 if (ea_name_len == name_len &&
Jeff Laytonac423442011-10-11 06:41:32 -04006176 memcmp(ea_name, temp_ptr, name_len) == 0) {
Jeff Layton31c05192010-02-10 16:18:26 -05006177 temp_ptr += name_len + 1;
6178 rc = value_len;
6179 if (buf_size == 0)
6180 goto QAllEAsOut;
6181 if ((size_t)value_len > buf_size) {
6182 rc = -ERANGE;
6183 goto QAllEAsOut;
6184 }
6185 memcpy(EAData, temp_ptr, value_len);
6186 goto QAllEAsOut;
6187 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006188 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05006189 /* account for prefix user. and trailing null */
6190 rc += (5 + 1 + name_len);
6191 if (rc < (int) buf_size) {
6192 memcpy(EAData, "user.", 5);
6193 EAData += 5;
6194 memcpy(EAData, temp_ptr, name_len);
6195 EAData += name_len;
6196 /* null terminate name */
6197 *EAData = 0;
6198 ++EAData;
6199 } else if (buf_size == 0) {
6200 /* skip copy - calc size only */
6201 } else {
6202 /* stop before overrun buffer */
6203 rc = -ERANGE;
6204 break;
6205 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006206 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05006207 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006208 temp_fea = (struct fea *)temp_ptr;
6209 }
6210
Jeff Layton31c05192010-02-10 16:18:26 -05006211 /* didn't find the named attribute */
6212 if (ea_name)
6213 rc = -ENODATA;
6214
Jeff Laytonf0d38682010-02-10 16:18:26 -05006215QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00006216 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006217 if (rc == -EAGAIN)
6218 goto QAllEAsRetry;
6219
6220 return (ssize_t)rc;
6221}
6222
Linus Torvalds1da177e2005-04-16 15:20:36 -07006223int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006224CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
6225 const char *fileName, const char *ea_name, const void *ea_value,
Steve French50c2f752007-07-13 00:33:32 +00006226 const __u16 ea_value_len, const struct nls_table *nls_codepage,
6227 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006228{
6229 struct smb_com_transaction2_spi_req *pSMB = NULL;
6230 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
6231 struct fealist *parm_data;
6232 int name_len;
6233 int rc = 0;
6234 int bytes_returned = 0;
6235 __u16 params, param_offset, byte_count, offset, count;
6236
Joe Perchesb6b38f72010-04-21 03:50:45 +00006237 cFYI(1, "In SetEA");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006238SetEARetry:
6239 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6240 (void **) &pSMBr);
6241 if (rc)
6242 return rc;
6243
6244 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6245 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006246 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
6247 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006248 name_len++; /* trailing null */
6249 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00006250 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006251 name_len = strnlen(fileName, PATH_MAX);
6252 name_len++; /* trailing null */
6253 strncpy(pSMB->FileName, fileName, name_len);
6254 }
6255
6256 params = 6 + name_len;
6257
6258 /* done calculating parms using name_len of file name,
6259 now use name_len to calculate length of ea name
6260 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00006261 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006262 name_len = 0;
6263 else
Steve French50c2f752007-07-13 00:33:32 +00006264 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006265
Steve Frenchdae5dbdb2007-12-30 23:49:57 +00006266 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006267 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006268 /* BB find max SMB PDU from sess */
6269 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006270 pSMB->MaxSetupCount = 0;
6271 pSMB->Reserved = 0;
6272 pSMB->Flags = 0;
6273 pSMB->Timeout = 0;
6274 pSMB->Reserved2 = 0;
6275 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006276 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006277 offset = param_offset + params;
6278 pSMB->InformationLevel =
6279 cpu_to_le16(SMB_SET_FILE_EA);
6280
6281 parm_data =
6282 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
6283 offset);
6284 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6285 pSMB->DataOffset = cpu_to_le16(offset);
6286 pSMB->SetupCount = 1;
6287 pSMB->Reserved3 = 0;
6288 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6289 byte_count = 3 /* pad */ + params + count;
6290 pSMB->DataCount = cpu_to_le16(count);
6291 parm_data->list_len = cpu_to_le32(count);
6292 parm_data->list[0].EA_flags = 0;
6293 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08006294 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006295 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00006296 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00006297 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006298 parm_data->list[0].name[name_len] = 0;
6299 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
6300 /* caller ensures that ea_value_len is less than 64K but
6301 we need to ensure that it fits within the smb */
6302
Steve French50c2f752007-07-13 00:33:32 +00006303 /*BB add length check to see if it would fit in
6304 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00006305 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
6306 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00006307 memcpy(parm_data->list[0].name+name_len+1,
6308 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006309
6310 pSMB->TotalDataCount = pSMB->DataCount;
6311 pSMB->ParameterCount = cpu_to_le16(params);
6312 pSMB->TotalParameterCount = pSMB->ParameterCount;
6313 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006314 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006315 pSMB->ByteCount = cpu_to_le16(byte_count);
6316 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6317 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006318 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00006319 cFYI(1, "SetPathInfo (EA) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006320
6321 cifs_buf_release(pSMB);
6322
6323 if (rc == -EAGAIN)
6324 goto SetEARetry;
6325
6326 return rc;
6327}
Linus Torvalds1da177e2005-04-16 15:20:36 -07006328#endif
Steve French0eff0e22011-02-24 05:39:23 +00006329
6330#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */
6331/*
6332 * Years ago the kernel added a "dnotify" function for Samba server,
6333 * to allow network clients (such as Windows) to display updated
6334 * lists of files in directory listings automatically when
6335 * files are added by one user when another user has the
6336 * same directory open on their desktop. The Linux cifs kernel
6337 * client hooked into the kernel side of this interface for
6338 * the same reason, but ironically when the VFS moved from
6339 * "dnotify" to "inotify" it became harder to plug in Linux
6340 * network file system clients (the most obvious use case
6341 * for notify interfaces is when multiple users can update
6342 * the contents of the same directory - exactly what network
6343 * file systems can do) although the server (Samba) could
6344 * still use it. For the short term we leave the worker
6345 * function ifdeffed out (below) until inotify is fixed
6346 * in the VFS to make it easier to plug in network file
6347 * system clients. If inotify turns out to be permanently
6348 * incompatible for network fs clients, we could instead simply
6349 * expose this config flag by adding a future cifs (and smb2) notify ioctl.
6350 */
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006351int CIFSSMBNotify(const unsigned int xid, struct cifs_tcon *tcon,
Steve French0eff0e22011-02-24 05:39:23 +00006352 const int notify_subdirs, const __u16 netfid,
6353 __u32 filter, struct file *pfile, int multishot,
6354 const struct nls_table *nls_codepage)
6355{
6356 int rc = 0;
6357 struct smb_com_transaction_change_notify_req *pSMB = NULL;
6358 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
6359 struct dir_notify_req *dnotify_req;
6360 int bytes_returned;
6361
6362 cFYI(1, "In CIFSSMBNotify for file handle %d", (int)netfid);
6363 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
6364 (void **) &pSMBr);
6365 if (rc)
6366 return rc;
6367
6368 pSMB->TotalParameterCount = 0 ;
6369 pSMB->TotalDataCount = 0;
6370 pSMB->MaxParameterCount = cpu_to_le32(2);
Jeff Laytonc974bef2011-10-11 06:41:32 -04006371 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Steve French0eff0e22011-02-24 05:39:23 +00006372 pSMB->MaxSetupCount = 4;
6373 pSMB->Reserved = 0;
6374 pSMB->ParameterOffset = 0;
6375 pSMB->DataCount = 0;
6376 pSMB->DataOffset = 0;
6377 pSMB->SetupCount = 4; /* single byte does not need le conversion */
6378 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
6379 pSMB->ParameterCount = pSMB->TotalParameterCount;
6380 if (notify_subdirs)
6381 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
6382 pSMB->Reserved2 = 0;
6383 pSMB->CompletionFilter = cpu_to_le32(filter);
6384 pSMB->Fid = netfid; /* file handle always le */
6385 pSMB->ByteCount = 0;
6386
6387 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6388 (struct smb_hdr *)pSMBr, &bytes_returned,
6389 CIFS_ASYNC_OP);
6390 if (rc) {
6391 cFYI(1, "Error in Notify = %d", rc);
6392 } else {
6393 /* Add file to outstanding requests */
6394 /* BB change to kmem cache alloc */
6395 dnotify_req = kmalloc(
6396 sizeof(struct dir_notify_req),
6397 GFP_KERNEL);
6398 if (dnotify_req) {
6399 dnotify_req->Pid = pSMB->hdr.Pid;
6400 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
6401 dnotify_req->Mid = pSMB->hdr.Mid;
6402 dnotify_req->Tid = pSMB->hdr.Tid;
6403 dnotify_req->Uid = pSMB->hdr.Uid;
6404 dnotify_req->netfid = netfid;
6405 dnotify_req->pfile = pfile;
6406 dnotify_req->filter = filter;
6407 dnotify_req->multishot = multishot;
6408 spin_lock(&GlobalMid_Lock);
6409 list_add_tail(&dnotify_req->lhead,
6410 &GlobalDnotifyReqList);
6411 spin_unlock(&GlobalMid_Lock);
6412 } else
6413 rc = -ENOMEM;
6414 }
6415 cifs_buf_release(pSMB);
6416 return rc;
6417}
6418#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */