blob: 074923ce593d7d53da6ae010128dffc8c080815b [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)) {
1579 if (cifs_verify_signature(rdata->iov, rdata->nr_iov,
1580 server, mid->sequence_number + 1))
1581 cERROR(1, "Unexpected SMB signature");
1582 }
1583 /* FIXME: should this be counted toward the initiating task? */
1584 task_io_account_read(rdata->bytes);
1585 cifs_stats_bytes_read(tcon, rdata->bytes);
1586 break;
1587 case MID_REQUEST_SUBMITTED:
1588 case MID_RETRY_NEEDED:
1589 rdata->result = -EAGAIN;
1590 break;
1591 default:
1592 rdata->result = -EIO;
1593 }
1594
Jeff Laytonda472fc2012-03-23 14:40:53 -04001595 queue_work(cifsiod_wq, &rdata->work);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001596 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04001597 add_credits(server, 1, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001598}
1599
1600/* cifs_async_readv - send an async write, and set up mid to handle result */
1601int
1602cifs_async_readv(struct cifs_readdata *rdata)
1603{
1604 int rc;
1605 READ_REQ *smb = NULL;
1606 int wct;
1607 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1608
1609 cFYI(1, "%s: offset=%llu bytes=%u", __func__,
1610 rdata->offset, rdata->bytes);
1611
1612 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1613 wct = 12;
1614 else {
1615 wct = 10; /* old style read */
1616 if ((rdata->offset >> 32) > 0) {
1617 /* can not handle this big offset for old */
1618 return -EIO;
1619 }
1620 }
1621
1622 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **)&smb);
1623 if (rc)
1624 return rc;
1625
1626 smb->hdr.Pid = cpu_to_le16((__u16)rdata->pid);
1627 smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16));
1628
1629 smb->AndXCommand = 0xFF; /* none */
1630 smb->Fid = rdata->cfile->netfid;
1631 smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF);
1632 if (wct == 12)
1633 smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32);
1634 smb->Remaining = 0;
1635 smb->MaxCount = cpu_to_le16(rdata->bytes & 0xFFFF);
1636 smb->MaxCountHigh = cpu_to_le32(rdata->bytes >> 16);
1637 if (wct == 12)
1638 smb->ByteCount = 0;
1639 else {
1640 /* old style read */
1641 struct smb_com_readx_req *smbr =
1642 (struct smb_com_readx_req *)smb;
1643 smbr->ByteCount = 0;
1644 }
1645
1646 /* 4 for RFC1001 length + 1 for BCC */
1647 rdata->iov[0].iov_base = smb;
1648 rdata->iov[0].iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
1649
Jeff Layton6993f742012-05-16 07:13:17 -04001650 kref_get(&rdata->refcount);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001651 rc = cifs_call_async(tcon->ses->server, rdata->iov, 1,
1652 cifs_readv_receive, cifs_readv_callback,
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04001653 rdata, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001654
1655 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001656 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Jeff Layton6993f742012-05-16 07:13:17 -04001657 else
1658 kref_put(&rdata->refcount, cifs_readdata_release);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001659
1660 cifs_small_buf_release(smb);
1661 return rc;
1662}
1663
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001665CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
1666 unsigned int *nbytes, char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001667{
1668 int rc = -EACCES;
1669 READ_REQ *pSMB = NULL;
1670 READ_RSP *pSMBr = NULL;
1671 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001672 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001673 int resp_buf_type = 0;
1674 struct kvec iov[1];
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001675 __u32 pid = io_parms->pid;
1676 __u16 netfid = io_parms->netfid;
1677 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001678 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001679 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680
Joe Perchesb6b38f72010-04-21 03:50:45 +00001681 cFYI(1, "Reading %d bytes on fid %d", count, netfid);
Steve French790fe572007-07-07 19:25:05 +00001682 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001683 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001684 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001685 wct = 10; /* old style read */
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001686 if ((offset >> 32) > 0) {
Steve French4c3130e2008-12-09 00:28:16 +00001687 /* can not handle this big offset for old */
1688 return -EIO;
1689 }
1690 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691
1692 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001693 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694 if (rc)
1695 return rc;
1696
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001697 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1698 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1699
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700 /* tcon and ses pointer are checked in smb_init */
1701 if (tcon->ses->server == NULL)
1702 return -ECONNABORTED;
1703
Steve Frenchec637e32005-12-12 20:53:18 -08001704 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705 pSMB->Fid = netfid;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001706 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001707 if (wct == 12)
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001708 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001709
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710 pSMB->Remaining = 0;
1711 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1712 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001713 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001714 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1715 else {
1716 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001717 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001718 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001719 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001720 }
Steve Frenchec637e32005-12-12 20:53:18 -08001721
1722 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001723 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve Frencha761ac52007-10-18 21:45:27 +00001724 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Jeff Layton77499812011-01-11 07:24:23 -05001725 &resp_buf_type, CIFS_LOG_ERROR);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001726 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001727 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001729 cERROR(1, "Send error in read = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730 } else {
1731 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1732 data_length = data_length << 16;
1733 data_length += le16_to_cpu(pSMBr->DataLength);
1734 *nbytes = data_length;
1735
1736 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001737 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001738 || (data_length > count)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001739 cFYI(1, "bad length %d for count %d",
1740 data_length, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741 rc = -EIO;
1742 *nbytes = 0;
1743 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001744 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001745 le16_to_cpu(pSMBr->DataOffset);
1746/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001747 cERROR(1, "Faulting on read rc = %d",rc);
Steve French50c2f752007-07-13 00:33:32 +00001748 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001749 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001750 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001751 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001752 }
1753 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001754
Steve French4b8f9302006-02-26 16:41:18 +00001755/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001756 if (*buf) {
1757 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001758 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001759 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001760 cifs_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001761 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001762 /* return buffer to caller to free */
1763 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001764 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001765 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001766 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001767 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001768 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001769
1770 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771 since file handle passed in no longer valid */
1772 return rc;
1773}
1774
Steve Frenchec637e32005-12-12 20:53:18 -08001775
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001777CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001778 unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001779 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780{
1781 int rc = -EACCES;
1782 WRITE_REQ *pSMB = NULL;
1783 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001784 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785 __u32 bytes_sent;
1786 __u16 byte_count;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001787 __u32 pid = io_parms->pid;
1788 __u16 netfid = io_parms->netfid;
1789 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001790 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001791 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001792
Steve Frencha24e2d72010-04-03 17:20:21 +00001793 *nbytes = 0;
1794
Joe Perchesb6b38f72010-04-21 03:50:45 +00001795 /* cFYI(1, "write at %lld %d bytes", offset, count);*/
Steve French790fe572007-07-07 19:25:05 +00001796 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001797 return -ECONNABORTED;
1798
Steve French790fe572007-07-07 19:25:05 +00001799 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001800 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001801 else {
Steve French1c955182005-08-30 20:58:07 -07001802 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001803 if ((offset >> 32) > 0) {
1804 /* can not handle big offset for old srv */
1805 return -EIO;
1806 }
1807 }
Steve French1c955182005-08-30 20:58:07 -07001808
1809 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810 (void **) &pSMBr);
1811 if (rc)
1812 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001813
1814 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1815 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1816
Linus Torvalds1da177e2005-04-16 15:20:36 -07001817 /* tcon and ses pointer are checked in smb_init */
1818 if (tcon->ses->server == NULL)
1819 return -ECONNABORTED;
1820
1821 pSMB->AndXCommand = 0xFF; /* none */
1822 pSMB->Fid = netfid;
1823 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001824 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001825 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001826
Linus Torvalds1da177e2005-04-16 15:20:36 -07001827 pSMB->Reserved = 0xFFFFFFFF;
1828 pSMB->WriteMode = 0;
1829 pSMB->Remaining = 0;
1830
Steve French50c2f752007-07-13 00:33:32 +00001831 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832 can send more if LARGE_WRITE_X capability returned by the server and if
1833 our buffer is big enough or if we convert to iovecs on socket writes
1834 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001835 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1837 } else {
1838 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1839 & ~0xFF;
1840 }
1841
1842 if (bytes_sent > count)
1843 bytes_sent = count;
1844 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001845 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001846 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001847 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001848 else if (ubuf) {
1849 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850 cifs_buf_release(pSMB);
1851 return -EFAULT;
1852 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001853 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854 /* No buffer */
1855 cifs_buf_release(pSMB);
1856 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001857 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001858 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001859 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001860 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001861 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001862
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1864 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001865 inc_rfc1001_len(pSMB, byte_count);
Steve French1c955182005-08-30 20:58:07 -07001866
Steve French790fe572007-07-07 19:25:05 +00001867 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001868 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001869 else { /* old style write has byte count 4 bytes earlier
1870 so 4 bytes pad */
1871 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001872 (struct smb_com_writex_req *)pSMB;
1873 pSMBW->ByteCount = cpu_to_le16(byte_count);
1874 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875
1876 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1877 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001878 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00001880 cFYI(1, "Send error in write = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881 } else {
1882 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1883 *nbytes = (*nbytes) << 16;
1884 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301885
1886 /*
1887 * Mask off high 16 bits when bytes written as returned by the
1888 * server is greater than bytes requested by the client. Some
1889 * OS/2 servers are known to set incorrect CountHigh values.
1890 */
1891 if (*nbytes > count)
1892 *nbytes &= 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893 }
1894
1895 cifs_buf_release(pSMB);
1896
Steve French50c2f752007-07-13 00:33:32 +00001897 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898 since file handle passed in no longer valid */
1899
1900 return rc;
1901}
1902
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001903void
1904cifs_writedata_release(struct kref *refcount)
1905{
1906 struct cifs_writedata *wdata = container_of(refcount,
1907 struct cifs_writedata, refcount);
1908
1909 if (wdata->cfile)
1910 cifsFileInfo_put(wdata->cfile);
1911
1912 kfree(wdata);
1913}
1914
1915/*
1916 * Write failed with a retryable error. Resend the write request. It's also
1917 * possible that the page was redirtied so re-clean the page.
1918 */
1919static void
1920cifs_writev_requeue(struct cifs_writedata *wdata)
1921{
1922 int i, rc;
1923 struct inode *inode = wdata->cfile->dentry->d_inode;
1924
1925 for (i = 0; i < wdata->nr_pages; i++) {
1926 lock_page(wdata->pages[i]);
1927 clear_page_dirty_for_io(wdata->pages[i]);
1928 }
1929
1930 do {
1931 rc = cifs_async_writev(wdata);
1932 } while (rc == -EAGAIN);
1933
1934 for (i = 0; i < wdata->nr_pages; i++) {
1935 if (rc != 0)
1936 SetPageError(wdata->pages[i]);
1937 unlock_page(wdata->pages[i]);
1938 }
1939
1940 mapping_set_error(inode->i_mapping, rc);
1941 kref_put(&wdata->refcount, cifs_writedata_release);
1942}
1943
Jeff Laytonc2e87642012-03-23 14:40:55 -04001944void
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001945cifs_writev_complete(struct work_struct *work)
1946{
1947 struct cifs_writedata *wdata = container_of(work,
1948 struct cifs_writedata, work);
1949 struct inode *inode = wdata->cfile->dentry->d_inode;
1950 int i = 0;
1951
1952 if (wdata->result == 0) {
Jeff Layton597b0272012-03-23 14:40:56 -04001953 spin_lock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001954 cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
Jeff Layton597b0272012-03-23 14:40:56 -04001955 spin_unlock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001956 cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
1957 wdata->bytes);
1958 } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
1959 return cifs_writev_requeue(wdata);
1960
1961 for (i = 0; i < wdata->nr_pages; i++) {
1962 struct page *page = wdata->pages[i];
1963 if (wdata->result == -EAGAIN)
1964 __set_page_dirty_nobuffers(page);
1965 else if (wdata->result < 0)
1966 SetPageError(page);
1967 end_page_writeback(page);
1968 page_cache_release(page);
1969 }
1970 if (wdata->result != -EAGAIN)
1971 mapping_set_error(inode->i_mapping, wdata->result);
1972 kref_put(&wdata->refcount, cifs_writedata_release);
1973}
1974
1975struct cifs_writedata *
Jeff Laytonc2e87642012-03-23 14:40:55 -04001976cifs_writedata_alloc(unsigned int nr_pages, work_func_t complete)
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001977{
1978 struct cifs_writedata *wdata;
1979
1980 /* this would overflow */
1981 if (nr_pages == 0) {
1982 cERROR(1, "%s: called with nr_pages == 0!", __func__);
1983 return NULL;
1984 }
1985
1986 /* writedata + number of page pointers */
1987 wdata = kzalloc(sizeof(*wdata) +
1988 sizeof(struct page *) * (nr_pages - 1), GFP_NOFS);
1989 if (wdata != NULL) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001990 kref_init(&wdata->refcount);
Jeff Laytonda82f7e2012-03-23 14:40:56 -04001991 INIT_LIST_HEAD(&wdata->list);
1992 init_completion(&wdata->done);
1993 INIT_WORK(&wdata->work, complete);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001994 }
1995 return wdata;
1996}
1997
1998/*
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001999 * Check the mid_state and signature on received buffer (if any), and queue the
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002000 * workqueue completion task.
2001 */
2002static void
2003cifs_writev_callback(struct mid_q_entry *mid)
2004{
2005 struct cifs_writedata *wdata = mid->callback_data;
Steve French96daf2b2011-05-27 04:34:02 +00002006 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002007 unsigned int written;
2008 WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
2009
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04002010 switch (mid->mid_state) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002011 case MID_RESPONSE_RECEIVED:
2012 wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
2013 if (wdata->result != 0)
2014 break;
2015
2016 written = le16_to_cpu(smb->CountHigh);
2017 written <<= 16;
2018 written += le16_to_cpu(smb->Count);
2019 /*
2020 * Mask off high 16 bits when bytes written as returned
2021 * by the server is greater than bytes requested by the
2022 * client. OS/2 servers are known to set incorrect
2023 * CountHigh values.
2024 */
2025 if (written > wdata->bytes)
2026 written &= 0xFFFF;
2027
2028 if (written < wdata->bytes)
2029 wdata->result = -ENOSPC;
2030 else
2031 wdata->bytes = written;
2032 break;
2033 case MID_REQUEST_SUBMITTED:
2034 case MID_RETRY_NEEDED:
2035 wdata->result = -EAGAIN;
2036 break;
2037 default:
2038 wdata->result = -EIO;
2039 break;
2040 }
2041
Jeff Laytonda472fc2012-03-23 14:40:53 -04002042 queue_work(cifsiod_wq, &wdata->work);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002043 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002044 add_credits(tcon->ses->server, 1, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002045}
2046
2047/* cifs_async_writev - send an async write, and set up mid to handle result */
2048int
2049cifs_async_writev(struct cifs_writedata *wdata)
2050{
2051 int i, rc = -EACCES;
2052 WRITE_REQ *smb = NULL;
2053 int wct;
Steve French96daf2b2011-05-27 04:34:02 +00002054 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002055 struct kvec *iov = NULL;
2056
2057 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
2058 wct = 14;
2059 } else {
2060 wct = 12;
2061 if (wdata->offset >> 32 > 0) {
2062 /* can not handle big offset for old srv */
2063 return -EIO;
2064 }
2065 }
2066
2067 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
2068 if (rc)
2069 goto async_writev_out;
2070
2071 /* 1 iov per page + 1 for header */
2072 iov = kzalloc((wdata->nr_pages + 1) * sizeof(*iov), GFP_NOFS);
2073 if (iov == NULL) {
2074 rc = -ENOMEM;
2075 goto async_writev_out;
2076 }
2077
Jeff Laytonfe5f5d22012-03-23 14:40:55 -04002078 smb->hdr.Pid = cpu_to_le16((__u16)wdata->pid);
2079 smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16));
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002080
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002081 smb->AndXCommand = 0xFF; /* none */
2082 smb->Fid = wdata->cfile->netfid;
2083 smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
2084 if (wct == 14)
2085 smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
2086 smb->Reserved = 0xFFFFFFFF;
2087 smb->WriteMode = 0;
2088 smb->Remaining = 0;
2089
2090 smb->DataOffset =
2091 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
2092
2093 /* 4 for RFC1001 length + 1 for BCC */
2094 iov[0].iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4 + 1;
2095 iov[0].iov_base = smb;
2096
Jeff Laytone9492872012-03-23 14:40:56 -04002097 /*
2098 * This function should marshal up the page array into the kvec
2099 * array, reserving [0] for the header. It should kmap the pages
2100 * and set the iov_len properly for each one. It may also set
2101 * wdata->bytes too.
2102 */
Jeff Layton3cf003c2012-07-11 09:09:36 -04002103 cifs_kmap_lock();
Jeff Laytone9492872012-03-23 14:40:56 -04002104 wdata->marshal_iov(iov, wdata);
Jeff Layton3cf003c2012-07-11 09:09:36 -04002105 cifs_kmap_unlock();
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002106
2107 cFYI(1, "async write at %llu %u bytes", wdata->offset, wdata->bytes);
2108
2109 smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
2110 smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16);
2111
2112 if (wct == 14) {
2113 inc_rfc1001_len(&smb->hdr, wdata->bytes + 1);
2114 put_bcc(wdata->bytes + 1, &smb->hdr);
2115 } else {
2116 /* wct == 12 */
2117 struct smb_com_writex_req *smbw =
2118 (struct smb_com_writex_req *)smb;
2119 inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
2120 put_bcc(wdata->bytes + 5, &smbw->hdr);
2121 iov[0].iov_len += 4; /* pad bigger by four bytes */
2122 }
2123
2124 kref_get(&wdata->refcount);
2125 rc = cifs_call_async(tcon->ses->server, iov, wdata->nr_pages + 1,
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002126 NULL, cifs_writev_callback, wdata, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002127
2128 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002129 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002130 else
2131 kref_put(&wdata->refcount, cifs_writedata_release);
2132
2133 /* send is done, unmap pages */
2134 for (i = 0; i < wdata->nr_pages; i++)
2135 kunmap(wdata->pages[i]);
2136
2137async_writev_out:
2138 cifs_small_buf_release(smb);
2139 kfree(iov);
2140 return rc;
2141}
2142
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002143int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002144CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002145 unsigned int *nbytes, struct kvec *iov, int n_vec,
2146 const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002147{
2148 int rc = -EACCES;
2149 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08002150 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002151 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08002152 int resp_buf_type = 0;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002153 __u32 pid = io_parms->pid;
2154 __u16 netfid = io_parms->netfid;
2155 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00002156 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002157 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002158
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04002159 *nbytes = 0;
2160
Joe Perchesb6b38f72010-04-21 03:50:45 +00002161 cFYI(1, "write2 at %lld %d bytes", (long long)offset, count);
Steve Frenchff7feac2005-11-15 16:45:16 -08002162
Steve French4c3130e2008-12-09 00:28:16 +00002163 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07002164 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00002165 } else {
Steve French8cc64c62005-10-03 13:49:43 -07002166 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00002167 if ((offset >> 32) > 0) {
2168 /* can not handle big offset for old srv */
2169 return -EIO;
2170 }
2171 }
Steve French8cc64c62005-10-03 13:49:43 -07002172 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002173 if (rc)
2174 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002175
2176 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
2177 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
2178
Linus Torvalds1da177e2005-04-16 15:20:36 -07002179 /* tcon and ses pointer are checked in smb_init */
2180 if (tcon->ses->server == NULL)
2181 return -ECONNABORTED;
2182
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002183 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002184 pSMB->Fid = netfid;
2185 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00002186 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002187 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002188 pSMB->Reserved = 0xFFFFFFFF;
2189 pSMB->WriteMode = 0;
2190 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002191
Linus Torvalds1da177e2005-04-16 15:20:36 -07002192 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00002193 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002194
Steve French3e844692005-10-03 13:37:24 -07002195 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
2196 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002197 /* header + 1 byte pad */
2198 smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
Steve French790fe572007-07-07 19:25:05 +00002199 if (wct == 14)
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002200 inc_rfc1001_len(pSMB, count + 1);
Steve French8cc64c62005-10-03 13:49:43 -07002201 else /* wct == 12 */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002202 inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
Steve French790fe572007-07-07 19:25:05 +00002203 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002204 pSMB->ByteCount = cpu_to_le16(count + 1);
2205 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00002206 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07002207 (struct smb_com_writex_req *)pSMB;
2208 pSMBW->ByteCount = cpu_to_le16(count + 5);
2209 }
Steve French3e844692005-10-03 13:37:24 -07002210 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00002211 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08002212 iov[0].iov_len = smb_hdr_len + 4;
2213 else /* wct == 12 pad bigger by four bytes */
2214 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00002215
Steve French3e844692005-10-03 13:37:24 -07002216
Steve Frenchec637e32005-12-12 20:53:18 -08002217 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French133672e2007-11-13 22:41:37 +00002218 long_op);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002219 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002220 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002221 cFYI(1, "Send error Write2 = %d", rc);
Steve French790fe572007-07-07 19:25:05 +00002222 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08002223 /* presumably this can not happen, but best to be safe */
2224 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002225 } else {
Steve Frenchad7a2922008-02-07 23:25:02 +00002226 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002227 *nbytes = le16_to_cpu(pSMBr->CountHigh);
2228 *nbytes = (*nbytes) << 16;
2229 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05302230
2231 /*
2232 * Mask off high 16 bits when bytes written as returned by the
2233 * server is greater than bytes requested by the client. OS/2
2234 * servers are known to set incorrect CountHigh values.
2235 */
2236 if (*nbytes > count)
2237 *nbytes &= 0xFFFF;
Steve French50c2f752007-07-13 00:33:32 +00002238 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002239
Steve French4b8f9302006-02-26 16:41:18 +00002240/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00002241 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002242 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00002243 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002244 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002245
Steve French50c2f752007-07-13 00:33:32 +00002246 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002247 since file handle passed in no longer valid */
2248
2249 return rc;
2250}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002251
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002252int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon,
2253 const __u16 netfid, const __u8 lock_type, const __u32 num_unlock,
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002254 const __u32 num_lock, LOCKING_ANDX_RANGE *buf)
2255{
2256 int rc = 0;
2257 LOCK_REQ *pSMB = NULL;
2258 struct kvec iov[2];
2259 int resp_buf_type;
2260 __u16 count;
2261
2262 cFYI(1, "cifs_lockv num lock %d num unlock %d", num_lock, num_unlock);
2263
2264 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2265 if (rc)
2266 return rc;
2267
2268 pSMB->Timeout = 0;
2269 pSMB->NumberOfLocks = cpu_to_le16(num_lock);
2270 pSMB->NumberOfUnlocks = cpu_to_le16(num_unlock);
2271 pSMB->LockType = lock_type;
2272 pSMB->AndXCommand = 0xFF; /* none */
2273 pSMB->Fid = netfid; /* netfid stays le */
2274
2275 count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2276 inc_rfc1001_len(pSMB, count);
2277 pSMB->ByteCount = cpu_to_le16(count);
2278
2279 iov[0].iov_base = (char *)pSMB;
2280 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 -
2281 (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2282 iov[1].iov_base = (char *)buf;
2283 iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2284
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002285 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002286 rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP);
2287 if (rc)
2288 cFYI(1, "Send error in cifs_lockv = %d", rc);
2289
2290 return rc;
2291}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002292
Linus Torvalds1da177e2005-04-16 15:20:36 -07002293int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002294CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002295 const __u16 smb_file_id, const __u32 netpid, const __u64 len,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002296 const __u64 offset, const __u32 numUnlock,
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002297 const __u32 numLock, const __u8 lockType,
2298 const bool waitFlag, const __u8 oplock_level)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002299{
2300 int rc = 0;
2301 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002302/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002303 int bytes_returned;
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002304 int flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002305 __u16 count;
2306
Joe Perchesb6b38f72010-04-21 03:50:45 +00002307 cFYI(1, "CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock);
Steve French46810cb2005-04-28 22:41:09 -07002308 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2309
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310 if (rc)
2311 return rc;
2312
Steve French790fe572007-07-07 19:25:05 +00002313 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002314 /* no response expected */
2315 flags = CIFS_ASYNC_OP | CIFS_OBREAK_OP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002316 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00002317 } else if (waitFlag) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002318 flags = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002319 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
2320 } else {
2321 pSMB->Timeout = 0;
2322 }
2323
2324 pSMB->NumberOfLocks = cpu_to_le16(numLock);
2325 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
2326 pSMB->LockType = lockType;
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002327 pSMB->OplockLevel = oplock_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002328 pSMB->AndXCommand = 0xFF; /* none */
2329 pSMB->Fid = smb_file_id; /* netfid stays le */
2330
Steve French790fe572007-07-07 19:25:05 +00002331 if ((numLock != 0) || (numUnlock != 0)) {
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002332 pSMB->Locks[0].Pid = cpu_to_le16(netpid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002333 /* BB where to store pid high? */
2334 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
2335 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
2336 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
2337 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
2338 count = sizeof(LOCKING_ANDX_RANGE);
2339 } else {
2340 /* oplock break */
2341 count = 0;
2342 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002343 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002344 pSMB->ByteCount = cpu_to_le16(count);
2345
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002346 if (waitFlag) {
2347 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002348 (struct smb_hdr *) pSMB, &bytes_returned);
Steve French133672e2007-11-13 22:41:37 +00002349 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002350 } else {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002351 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, flags);
Steve French133672e2007-11-13 22:41:37 +00002352 /* SMB buffer freed by function above */
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002353 }
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002354 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002355 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002356 cFYI(1, "Send error in Lock = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002357
Steve French50c2f752007-07-13 00:33:32 +00002358 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002359 since file handle passed in no longer valid */
2360 return rc;
2361}
2362
2363int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002364CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002365 const __u16 smb_file_id, const __u32 netpid,
2366 const loff_t start_offset, const __u64 len,
2367 struct file_lock *pLockData, const __u16 lock_type,
2368 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00002369{
2370 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2371 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00002372 struct cifs_posix_lock *parm_data;
2373 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00002374 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00002375 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00002376 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00002377 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00002378 struct kvec iov[1];
Steve French08547b02006-02-28 22:39:25 +00002379
Joe Perchesb6b38f72010-04-21 03:50:45 +00002380 cFYI(1, "Posix Lock");
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002381
Steve French08547b02006-02-28 22:39:25 +00002382 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
2383
2384 if (rc)
2385 return rc;
2386
2387 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
2388
Steve French50c2f752007-07-13 00:33:32 +00002389 params = 6;
Steve French08547b02006-02-28 22:39:25 +00002390 pSMB->MaxSetupCount = 0;
2391 pSMB->Reserved = 0;
2392 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00002393 pSMB->Reserved2 = 0;
2394 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2395 offset = param_offset + params;
2396
Steve French08547b02006-02-28 22:39:25 +00002397 count = sizeof(struct cifs_posix_lock);
2398 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002399 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00002400 pSMB->SetupCount = 1;
2401 pSMB->Reserved3 = 0;
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002402 if (pLockData)
Steve French08547b02006-02-28 22:39:25 +00002403 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2404 else
2405 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2406 byte_count = 3 /* pad */ + params + count;
2407 pSMB->DataCount = cpu_to_le16(count);
2408 pSMB->ParameterCount = cpu_to_le16(params);
2409 pSMB->TotalDataCount = pSMB->DataCount;
2410 pSMB->TotalParameterCount = pSMB->ParameterCount;
2411 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00002412 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00002413 (((char *) &pSMB->hdr.Protocol) + offset);
2414
2415 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00002416 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00002417 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00002418 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00002419 pSMB->Timeout = cpu_to_le32(-1);
2420 } else
2421 pSMB->Timeout = 0;
2422
Pavel Shilovsky4f6bcec2011-10-22 15:33:30 +04002423 parm_data->pid = cpu_to_le32(netpid);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002424 parm_data->start = cpu_to_le64(start_offset);
Steve Frenchcec6815a2006-05-30 18:07:17 +00002425 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00002426
2427 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00002428 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00002429 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
2430 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002431 inc_rfc1001_len(pSMB, byte_count);
Steve French08547b02006-02-28 22:39:25 +00002432 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002433 if (waitFlag) {
2434 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2435 (struct smb_hdr *) pSMBr, &bytes_returned);
2436 } else {
Steve French133672e2007-11-13 22:41:37 +00002437 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002438 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French133672e2007-11-13 22:41:37 +00002439 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
2440 &resp_buf_type, timeout);
2441 pSMB = NULL; /* request buf already freed by SendReceive2. Do
2442 not try to free it twice below on exit */
2443 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002444 }
2445
Steve French08547b02006-02-28 22:39:25 +00002446 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002447 cFYI(1, "Send error in Posix Lock = %d", rc);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002448 } else if (pLockData) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002449 /* lock structure can be returned on get */
2450 __u16 data_offset;
2451 __u16 data_count;
2452 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00002453
Jeff Layton820a8032011-05-04 08:05:26 -04002454 if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002455 rc = -EIO; /* bad smb */
2456 goto plk_err_exit;
2457 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002458 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2459 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00002460 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002461 rc = -EIO;
2462 goto plk_err_exit;
2463 }
2464 parm_data = (struct cifs_posix_lock *)
2465 ((char *)&pSMBr->hdr.Protocol + data_offset);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002466 if (parm_data->lock_type == __constant_cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002467 pLockData->fl_type = F_UNLCK;
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002468 else {
2469 if (parm_data->lock_type ==
2470 __constant_cpu_to_le16(CIFS_RDLCK))
2471 pLockData->fl_type = F_RDLCK;
2472 else if (parm_data->lock_type ==
2473 __constant_cpu_to_le16(CIFS_WRLCK))
2474 pLockData->fl_type = F_WRLCK;
2475
Steve French5443d132011-03-13 05:08:25 +00002476 pLockData->fl_start = le64_to_cpu(parm_data->start);
2477 pLockData->fl_end = pLockData->fl_start +
2478 le64_to_cpu(parm_data->length) - 1;
2479 pLockData->fl_pid = le32_to_cpu(parm_data->pid);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002480 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002481 }
Steve French50c2f752007-07-13 00:33:32 +00002482
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002483plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00002484 if (pSMB)
2485 cifs_small_buf_release(pSMB);
2486
Steve French133672e2007-11-13 22:41:37 +00002487 if (resp_buf_type == CIFS_SMALL_BUFFER)
2488 cifs_small_buf_release(iov[0].iov_base);
2489 else if (resp_buf_type == CIFS_LARGE_BUFFER)
2490 cifs_buf_release(iov[0].iov_base);
2491
Steve French08547b02006-02-28 22:39:25 +00002492 /* Note: On -EAGAIN error only caller can retry on handle based calls
2493 since file handle passed in no longer valid */
2494
2495 return rc;
2496}
2497
2498
2499int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002500CIFSSMBClose(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002501{
2502 int rc = 0;
2503 CLOSE_REQ *pSMB = NULL;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002504 cFYI(1, "In CIFSSMBClose");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002505
2506/* do not retry on dead session on close */
2507 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00002508 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002509 return 0;
2510 if (rc)
2511 return rc;
2512
Linus Torvalds1da177e2005-04-16 15:20:36 -07002513 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00002514 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002516 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002517 cifs_stats_inc(&tcon->stats.cifs_stats.num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002518 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00002519 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002520 /* EINTR is expected when user ctl-c to kill app */
Joe Perchesb6b38f72010-04-21 03:50:45 +00002521 cERROR(1, "Send error in Close = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002522 }
2523 }
2524
Linus Torvalds1da177e2005-04-16 15:20:36 -07002525 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00002526 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002527 rc = 0;
2528
2529 return rc;
2530}
2531
2532int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002533CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Steve Frenchb298f222009-02-21 21:17:43 +00002534{
2535 int rc = 0;
2536 FLUSH_REQ *pSMB = NULL;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002537 cFYI(1, "In CIFSSMBFlush");
Steve Frenchb298f222009-02-21 21:17:43 +00002538
2539 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
2540 if (rc)
2541 return rc;
2542
2543 pSMB->FileID = (__u16) smb_file_id;
2544 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002545 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002546 cifs_stats_inc(&tcon->stats.cifs_stats.num_flushes);
Steve Frenchb298f222009-02-21 21:17:43 +00002547 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002548 cERROR(1, "Send error in Flush = %d", rc);
Steve Frenchb298f222009-02-21 21:17:43 +00002549
2550 return rc;
2551}
2552
2553int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002554CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002555 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002556 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002557{
2558 int rc = 0;
2559 RENAME_REQ *pSMB = NULL;
2560 RENAME_RSP *pSMBr = NULL;
2561 int bytes_returned;
2562 int name_len, name_len2;
2563 __u16 count;
2564
Joe Perchesb6b38f72010-04-21 03:50:45 +00002565 cFYI(1, "In CIFSSMBRename");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002566renameRetry:
2567 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
2568 (void **) &pSMBr);
2569 if (rc)
2570 return rc;
2571
2572 pSMB->BufferFormat = 0x04;
2573 pSMB->SearchAttributes =
2574 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2575 ATTR_DIRECTORY);
2576
2577 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2578 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06002579 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, fromName,
2580 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002581 name_len++; /* trailing null */
2582 name_len *= 2;
2583 pSMB->OldFileName[name_len] = 0x04; /* pad */
2584 /* protocol requires ASCII signature byte on Unicode string */
2585 pSMB->OldFileName[name_len + 1] = 0x00;
2586 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002587 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2588 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002589 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2590 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002591 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002592 name_len = strnlen(fromName, PATH_MAX);
2593 name_len++; /* trailing null */
2594 strncpy(pSMB->OldFileName, fromName, name_len);
2595 name_len2 = strnlen(toName, PATH_MAX);
2596 name_len2++; /* trailing null */
2597 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2598 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2599 name_len2++; /* trailing null */
2600 name_len2++; /* signature byte */
2601 }
2602
2603 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002604 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002605 pSMB->ByteCount = cpu_to_le16(count);
2606
2607 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2608 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002609 cifs_stats_inc(&tcon->stats.cifs_stats.num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002610 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002611 cFYI(1, "Send error in rename = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002612
Linus Torvalds1da177e2005-04-16 15:20:36 -07002613 cifs_buf_release(pSMB);
2614
2615 if (rc == -EAGAIN)
2616 goto renameRetry;
2617
2618 return rc;
2619}
2620
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002621int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002622 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002623 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002624{
2625 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2626 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002627 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002628 char *data_offset;
2629 char dummy_string[30];
2630 int rc = 0;
2631 int bytes_returned = 0;
2632 int len_of_str;
2633 __u16 params, param_offset, offset, count, byte_count;
2634
Joe Perchesb6b38f72010-04-21 03:50:45 +00002635 cFYI(1, "Rename to File by handle");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002636 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2637 (void **) &pSMBr);
2638 if (rc)
2639 return rc;
2640
2641 params = 6;
2642 pSMB->MaxSetupCount = 0;
2643 pSMB->Reserved = 0;
2644 pSMB->Flags = 0;
2645 pSMB->Timeout = 0;
2646 pSMB->Reserved2 = 0;
2647 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2648 offset = param_offset + params;
2649
2650 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2651 rename_info = (struct set_file_rename *) data_offset;
2652 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002653 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002654 pSMB->SetupCount = 1;
2655 pSMB->Reserved3 = 0;
2656 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2657 byte_count = 3 /* pad */ + params;
2658 pSMB->ParameterCount = cpu_to_le16(params);
2659 pSMB->TotalParameterCount = pSMB->ParameterCount;
2660 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2661 pSMB->DataOffset = cpu_to_le16(offset);
2662 /* construct random name ".cifs_tmp<inodenum><mid>" */
2663 rename_info->overwrite = cpu_to_le32(1);
2664 rename_info->root_fid = 0;
2665 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002666 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002667 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
Steve Frenchacbbb762012-01-18 22:32:33 -06002668 len_of_str =
2669 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002670 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002671 } else {
Steve Frenchacbbb762012-01-18 22:32:33 -06002672 len_of_str =
2673 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002674 target_name, PATH_MAX, nls_codepage,
2675 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002676 }
2677 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002678 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002679 byte_count += count;
2680 pSMB->DataCount = cpu_to_le16(count);
2681 pSMB->TotalDataCount = pSMB->DataCount;
2682 pSMB->Fid = netfid;
2683 pSMB->InformationLevel =
2684 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2685 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002686 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002687 pSMB->ByteCount = cpu_to_le16(byte_count);
2688 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002689 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002690 cifs_stats_inc(&pTcon->stats.cifs_stats.num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002691 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002692 cFYI(1, "Send error in Rename (by file handle) = %d", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07002693
Linus Torvalds1da177e2005-04-16 15:20:36 -07002694 cifs_buf_release(pSMB);
2695
2696 /* Note: On -EAGAIN error only caller can retry on handle based calls
2697 since file handle passed in no longer valid */
2698
2699 return rc;
2700}
2701
2702int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002703CIFSSMBCopy(const unsigned int xid, struct cifs_tcon *tcon,
2704 const char *fromName, const __u16 target_tid, const char *toName,
2705 const int flags, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002706{
2707 int rc = 0;
2708 COPY_REQ *pSMB = NULL;
2709 COPY_RSP *pSMBr = NULL;
2710 int bytes_returned;
2711 int name_len, name_len2;
2712 __u16 count;
2713
Joe Perchesb6b38f72010-04-21 03:50:45 +00002714 cFYI(1, "In CIFSSMBCopy");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002715copyRetry:
2716 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2717 (void **) &pSMBr);
2718 if (rc)
2719 return rc;
2720
2721 pSMB->BufferFormat = 0x04;
2722 pSMB->Tid2 = target_tid;
2723
2724 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2725
2726 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002727 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2728 fromName, PATH_MAX, nls_codepage,
2729 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002730 name_len++; /* trailing null */
2731 name_len *= 2;
2732 pSMB->OldFileName[name_len] = 0x04; /* pad */
2733 /* protocol requires ASCII signature byte on Unicode string */
2734 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002735 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002736 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2737 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002738 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2739 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002740 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002741 name_len = strnlen(fromName, PATH_MAX);
2742 name_len++; /* trailing null */
2743 strncpy(pSMB->OldFileName, fromName, name_len);
2744 name_len2 = strnlen(toName, PATH_MAX);
2745 name_len2++; /* trailing null */
2746 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2747 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2748 name_len2++; /* trailing null */
2749 name_len2++; /* signature byte */
2750 }
2751
2752 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002753 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002754 pSMB->ByteCount = cpu_to_le16(count);
2755
2756 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2757 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2758 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002759 cFYI(1, "Send error in copy = %d with %d files copied",
2760 rc, le16_to_cpu(pSMBr->CopyCount));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002761 }
Steve French0d817bc2008-05-22 02:02:03 +00002762 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002763
2764 if (rc == -EAGAIN)
2765 goto copyRetry;
2766
2767 return rc;
2768}
2769
2770int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002771CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002772 const char *fromName, const char *toName,
2773 const struct nls_table *nls_codepage)
2774{
2775 TRANSACTION2_SPI_REQ *pSMB = NULL;
2776 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2777 char *data_offset;
2778 int name_len;
2779 int name_len_target;
2780 int rc = 0;
2781 int bytes_returned = 0;
2782 __u16 params, param_offset, offset, byte_count;
2783
Joe Perchesb6b38f72010-04-21 03:50:45 +00002784 cFYI(1, "In Symlink Unix style");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002785createSymLinkRetry:
2786 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2787 (void **) &pSMBr);
2788 if (rc)
2789 return rc;
2790
2791 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2792 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06002793 cifs_strtoUTF16((__le16 *) pSMB->FileName, fromName,
2794 /* find define for this maxpathcomponent */
2795 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796 name_len++; /* trailing null */
2797 name_len *= 2;
2798
Steve French50c2f752007-07-13 00:33:32 +00002799 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002800 name_len = strnlen(fromName, PATH_MAX);
2801 name_len++; /* trailing null */
2802 strncpy(pSMB->FileName, fromName, name_len);
2803 }
2804 params = 6 + name_len;
2805 pSMB->MaxSetupCount = 0;
2806 pSMB->Reserved = 0;
2807 pSMB->Flags = 0;
2808 pSMB->Timeout = 0;
2809 pSMB->Reserved2 = 0;
2810 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002811 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002812 offset = param_offset + params;
2813
2814 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2815 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2816 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06002817 cifs_strtoUTF16((__le16 *) data_offset, toName, PATH_MAX
2818 /* find define for this maxpathcomponent */
2819 , nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002820 name_len_target++; /* trailing null */
2821 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002822 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002823 name_len_target = strnlen(toName, PATH_MAX);
2824 name_len_target++; /* trailing null */
2825 strncpy(data_offset, toName, name_len_target);
2826 }
2827
2828 pSMB->MaxParameterCount = cpu_to_le16(2);
2829 /* BB find exact max on data count below from sess */
2830 pSMB->MaxDataCount = cpu_to_le16(1000);
2831 pSMB->SetupCount = 1;
2832 pSMB->Reserved3 = 0;
2833 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2834 byte_count = 3 /* pad */ + params + name_len_target;
2835 pSMB->DataCount = cpu_to_le16(name_len_target);
2836 pSMB->ParameterCount = cpu_to_le16(params);
2837 pSMB->TotalDataCount = pSMB->DataCount;
2838 pSMB->TotalParameterCount = pSMB->ParameterCount;
2839 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2840 pSMB->DataOffset = cpu_to_le16(offset);
2841 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2842 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002843 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002844 pSMB->ByteCount = cpu_to_le16(byte_count);
2845 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2846 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002847 cifs_stats_inc(&tcon->stats.cifs_stats.num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002848 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002849 cFYI(1, "Send error in SetPathInfo create symlink = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002850
Steve French0d817bc2008-05-22 02:02:03 +00002851 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002852
2853 if (rc == -EAGAIN)
2854 goto createSymLinkRetry;
2855
2856 return rc;
2857}
2858
2859int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002860CIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002861 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002862 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002863{
2864 TRANSACTION2_SPI_REQ *pSMB = NULL;
2865 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2866 char *data_offset;
2867 int name_len;
2868 int name_len_target;
2869 int rc = 0;
2870 int bytes_returned = 0;
2871 __u16 params, param_offset, offset, byte_count;
2872
Joe Perchesb6b38f72010-04-21 03:50:45 +00002873 cFYI(1, "In Create Hard link Unix style");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002874createHardLinkRetry:
2875 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2876 (void **) &pSMBr);
2877 if (rc)
2878 return rc;
2879
2880 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002881 name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, toName,
2882 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002883 name_len++; /* trailing null */
2884 name_len *= 2;
2885
Steve French50c2f752007-07-13 00:33:32 +00002886 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002887 name_len = strnlen(toName, PATH_MAX);
2888 name_len++; /* trailing null */
2889 strncpy(pSMB->FileName, toName, name_len);
2890 }
2891 params = 6 + name_len;
2892 pSMB->MaxSetupCount = 0;
2893 pSMB->Reserved = 0;
2894 pSMB->Flags = 0;
2895 pSMB->Timeout = 0;
2896 pSMB->Reserved2 = 0;
2897 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002898 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002899 offset = param_offset + params;
2900
2901 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2902 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2903 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06002904 cifsConvertToUTF16((__le16 *) data_offset, fromName,
2905 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002906 name_len_target++; /* trailing null */
2907 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002908 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002909 name_len_target = strnlen(fromName, PATH_MAX);
2910 name_len_target++; /* trailing null */
2911 strncpy(data_offset, fromName, name_len_target);
2912 }
2913
2914 pSMB->MaxParameterCount = cpu_to_le16(2);
2915 /* BB find exact max on data count below from sess*/
2916 pSMB->MaxDataCount = cpu_to_le16(1000);
2917 pSMB->SetupCount = 1;
2918 pSMB->Reserved3 = 0;
2919 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2920 byte_count = 3 /* pad */ + params + name_len_target;
2921 pSMB->ParameterCount = cpu_to_le16(params);
2922 pSMB->TotalParameterCount = pSMB->ParameterCount;
2923 pSMB->DataCount = cpu_to_le16(name_len_target);
2924 pSMB->TotalDataCount = pSMB->DataCount;
2925 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2926 pSMB->DataOffset = cpu_to_le16(offset);
2927 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2928 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002929 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002930 pSMB->ByteCount = cpu_to_le16(byte_count);
2931 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2932 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002933 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002934 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002935 cFYI(1, "Send error in SetPathInfo (hard link) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002936
2937 cifs_buf_release(pSMB);
2938 if (rc == -EAGAIN)
2939 goto createHardLinkRetry;
2940
2941 return rc;
2942}
2943
2944int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002945CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002946 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002947 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002948{
2949 int rc = 0;
2950 NT_RENAME_REQ *pSMB = NULL;
2951 RENAME_RSP *pSMBr = NULL;
2952 int bytes_returned;
2953 int name_len, name_len2;
2954 __u16 count;
2955
Joe Perchesb6b38f72010-04-21 03:50:45 +00002956 cFYI(1, "In CIFSCreateHardLink");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002957winCreateHardLinkRetry:
2958
2959 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2960 (void **) &pSMBr);
2961 if (rc)
2962 return rc;
2963
2964 pSMB->SearchAttributes =
2965 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2966 ATTR_DIRECTORY);
2967 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2968 pSMB->ClusterCount = 0;
2969
2970 pSMB->BufferFormat = 0x04;
2971
2972 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2973 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06002974 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, fromName,
2975 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002976 name_len++; /* trailing null */
2977 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05002978
2979 /* protocol specifies ASCII buffer format (0x04) for unicode */
2980 pSMB->OldFileName[name_len] = 0x04;
2981 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002982 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002983 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2984 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002985 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2986 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002987 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002988 name_len = strnlen(fromName, PATH_MAX);
2989 name_len++; /* trailing null */
2990 strncpy(pSMB->OldFileName, fromName, name_len);
2991 name_len2 = strnlen(toName, PATH_MAX);
2992 name_len2++; /* trailing null */
2993 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2994 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2995 name_len2++; /* trailing null */
2996 name_len2++; /* signature byte */
2997 }
2998
2999 count = 1 /* string type byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003000 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003001 pSMB->ByteCount = cpu_to_le16(count);
3002
3003 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3004 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003005 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00003006 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003007 cFYI(1, "Send error in hard link (NT rename) = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00003008
Linus Torvalds1da177e2005-04-16 15:20:36 -07003009 cifs_buf_release(pSMB);
3010 if (rc == -EAGAIN)
3011 goto winCreateHardLinkRetry;
3012
3013 return rc;
3014}
3015
3016int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003017CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04003018 const unsigned char *searchName, char **symlinkinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003019 const struct nls_table *nls_codepage)
3020{
3021/* SMB_QUERY_FILE_UNIX_LINK */
3022 TRANSACTION2_QPI_REQ *pSMB = NULL;
3023 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3024 int rc = 0;
3025 int bytes_returned;
3026 int name_len;
3027 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04003028 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003029
Joe Perchesb6b38f72010-04-21 03:50:45 +00003030 cFYI(1, "In QPathSymLinkInfo (Unix) for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003031
3032querySymLinkRetry:
3033 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3034 (void **) &pSMBr);
3035 if (rc)
3036 return rc;
3037
3038 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3039 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003040 cifs_strtoUTF16((__le16 *) pSMB->FileName, searchName,
3041 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003042 name_len++; /* trailing null */
3043 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003044 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003045 name_len = strnlen(searchName, PATH_MAX);
3046 name_len++; /* trailing null */
3047 strncpy(pSMB->FileName, searchName, name_len);
3048 }
3049
3050 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3051 pSMB->TotalDataCount = 0;
3052 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04003053 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003054 pSMB->MaxSetupCount = 0;
3055 pSMB->Reserved = 0;
3056 pSMB->Flags = 0;
3057 pSMB->Timeout = 0;
3058 pSMB->Reserved2 = 0;
3059 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003060 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003061 pSMB->DataCount = 0;
3062 pSMB->DataOffset = 0;
3063 pSMB->SetupCount = 1;
3064 pSMB->Reserved3 = 0;
3065 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3066 byte_count = params + 1 /* pad */ ;
3067 pSMB->TotalParameterCount = cpu_to_le16(params);
3068 pSMB->ParameterCount = pSMB->TotalParameterCount;
3069 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
3070 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003071 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003072 pSMB->ByteCount = cpu_to_le16(byte_count);
3073
3074 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3075 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3076 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003077 cFYI(1, "Send error in QuerySymLinkInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003078 } else {
3079 /* decode response */
3080
3081 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003082 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003083 if (rc || get_bcc(&pSMBr->hdr) < 2)
Jeff Layton460b9692009-04-30 07:17:56 -04003084 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003085 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00003086 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04003087 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003088
Jeff Layton460b9692009-04-30 07:17:56 -04003089 data_start = ((char *) &pSMBr->hdr.Protocol) +
3090 le16_to_cpu(pSMBr->t2.DataOffset);
3091
Steve French0e0d2cf2009-05-01 05:27:32 +00003092 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3093 is_unicode = true;
3094 else
3095 is_unicode = false;
3096
Steve French737b7582005-04-28 22:41:06 -07003097 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchacbbb762012-01-18 22:32:33 -06003098 *symlinkinfo = cifs_strndup_from_utf16(data_start,
3099 count, is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04003100 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04003101 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003102 }
3103 }
3104 cifs_buf_release(pSMB);
3105 if (rc == -EAGAIN)
3106 goto querySymLinkRetry;
3107 return rc;
3108}
3109
Steve Frenchc52a9552011-02-24 06:16:22 +00003110#ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL
3111/*
3112 * Recent Windows versions now create symlinks more frequently
3113 * and they use the "reparse point" mechanism below. We can of course
3114 * do symlinks nicely to Samba and other servers which support the
3115 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
3116 * "MF" symlinks optionally, but for recent Windows we really need to
3117 * reenable the code below and fix the cifs_symlink callers to handle this.
3118 * In the interim this code has been moved to its own config option so
3119 * it is not compiled in by default until callers fixed up and more tested.
3120 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003121int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003122CIFSSMBQueryReparseLinkInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003123 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00003124 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003125 const struct nls_table *nls_codepage)
3126{
3127 int rc = 0;
3128 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00003129 struct smb_com_transaction_ioctl_req *pSMB;
3130 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003131
Joe Perchesb6b38f72010-04-21 03:50:45 +00003132 cFYI(1, "In Windows reparse style QueryLink for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003133 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3134 (void **) &pSMBr);
3135 if (rc)
3136 return rc;
3137
3138 pSMB->TotalParameterCount = 0 ;
3139 pSMB->TotalDataCount = 0;
3140 pSMB->MaxParameterCount = cpu_to_le32(2);
3141 /* BB find exact data count max from sess structure BB */
Jeff Laytonc974bef2011-10-11 06:41:32 -04003142 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003143 pSMB->MaxSetupCount = 4;
3144 pSMB->Reserved = 0;
3145 pSMB->ParameterOffset = 0;
3146 pSMB->DataCount = 0;
3147 pSMB->DataOffset = 0;
3148 pSMB->SetupCount = 4;
3149 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
3150 pSMB->ParameterCount = pSMB->TotalParameterCount;
3151 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
3152 pSMB->IsFsctl = 1; /* FSCTL */
3153 pSMB->IsRootFlag = 0;
3154 pSMB->Fid = fid; /* file handle always le */
3155 pSMB->ByteCount = 0;
3156
3157 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3158 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3159 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003160 cFYI(1, "Send error in QueryReparseLinkInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003161 } else { /* decode response */
3162 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
3163 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
Jeff Layton820a8032011-05-04 08:05:26 -04003164 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
3165 /* BB also check enough total bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003166 rc = -EIO; /* bad smb */
Steve Frenchafe48c32009-05-02 05:25:46 +00003167 goto qreparse_out;
3168 }
3169 if (data_count && (data_count < 2048)) {
3170 char *end_of_smb = 2 /* sizeof byte count */ +
Jeff Layton820a8032011-05-04 08:05:26 -04003171 get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003172
Steve Frenchafe48c32009-05-02 05:25:46 +00003173 struct reparse_data *reparse_buf =
Steve French50c2f752007-07-13 00:33:32 +00003174 (struct reparse_data *)
3175 ((char *)&pSMBr->hdr.Protocol
3176 + data_offset);
Steve Frenchafe48c32009-05-02 05:25:46 +00003177 if ((char *)reparse_buf >= end_of_smb) {
3178 rc = -EIO;
3179 goto qreparse_out;
3180 }
3181 if ((reparse_buf->LinkNamesBuf +
3182 reparse_buf->TargetNameOffset +
3183 reparse_buf->TargetNameLen) > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003184 cFYI(1, "reparse buf beyond SMB");
Steve Frenchafe48c32009-05-02 05:25:46 +00003185 rc = -EIO;
3186 goto qreparse_out;
3187 }
Steve French50c2f752007-07-13 00:33:32 +00003188
Steve Frenchafe48c32009-05-02 05:25:46 +00003189 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3190 cifs_from_ucs2(symlinkinfo, (__le16 *)
Steve French50c2f752007-07-13 00:33:32 +00003191 (reparse_buf->LinkNamesBuf +
3192 reparse_buf->TargetNameOffset),
Steve Frenchafe48c32009-05-02 05:25:46 +00003193 buflen,
3194 reparse_buf->TargetNameLen,
3195 nls_codepage, 0);
3196 } else { /* ASCII names */
3197 strncpy(symlinkinfo,
3198 reparse_buf->LinkNamesBuf +
3199 reparse_buf->TargetNameOffset,
3200 min_t(const int, buflen,
3201 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003202 }
Steve Frenchafe48c32009-05-02 05:25:46 +00003203 } else {
3204 rc = -EIO;
Joe Perchesb6b38f72010-04-21 03:50:45 +00003205 cFYI(1, "Invalid return data count on "
3206 "get reparse info ioctl");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003207 }
Steve Frenchafe48c32009-05-02 05:25:46 +00003208 symlinkinfo[buflen] = 0; /* just in case so the caller
3209 does not go off the end of the buffer */
Joe Perchesb6b38f72010-04-21 03:50:45 +00003210 cFYI(1, "readlink result - %s", symlinkinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003211 }
Steve French989c7e52009-05-02 05:32:20 +00003212
Linus Torvalds1da177e2005-04-16 15:20:36 -07003213qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07003214 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003215
3216 /* Note: On -EAGAIN error only caller can retry on handle based calls
3217 since file handle passed in no longer valid */
3218
3219 return rc;
3220}
Steve Frenchc52a9552011-02-24 06:16:22 +00003221#endif /* CIFS_SYMLINK_EXPERIMENTAL */ /* BB temporarily unused */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003222
3223#ifdef CONFIG_CIFS_POSIX
3224
3225/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00003226static void cifs_convert_ace(posix_acl_xattr_entry *ace,
3227 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003228{
3229 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08003230 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
3231 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
3232 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesb6b38f72010-04-21 03:50:45 +00003233 /* cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003234
3235 return;
3236}
3237
3238/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00003239static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
3240 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003241{
3242 int size = 0;
3243 int i;
3244 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00003245 struct cifs_posix_ace *pACE;
3246 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
3247 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003248
3249 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
3250 return -EOPNOTSUPP;
3251
Steve French790fe572007-07-07 19:25:05 +00003252 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003253 count = le16_to_cpu(cifs_acl->access_entry_count);
3254 pACE = &cifs_acl->ace_array[0];
3255 size = sizeof(struct cifs_posix_acl);
3256 size += sizeof(struct cifs_posix_ace) * count;
3257 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003258 if (size_of_data_area < size) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003259 cFYI(1, "bad CIFS POSIX ACL size %d vs. %d",
3260 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003261 return -EINVAL;
3262 }
Steve French790fe572007-07-07 19:25:05 +00003263 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003264 count = le16_to_cpu(cifs_acl->access_entry_count);
3265 size = sizeof(struct cifs_posix_acl);
3266 size += sizeof(struct cifs_posix_ace) * count;
3267/* skip past access ACEs to get to default ACEs */
3268 pACE = &cifs_acl->ace_array[count];
3269 count = le16_to_cpu(cifs_acl->default_entry_count);
3270 size += sizeof(struct cifs_posix_ace) * count;
3271 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003272 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003273 return -EINVAL;
3274 } else {
3275 /* illegal type */
3276 return -EINVAL;
3277 }
3278
3279 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00003280 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00003281 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00003282 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003283 return -ERANGE;
3284 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08003285 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00003286 for (i = 0; i < count ; i++) {
3287 cifs_convert_ace(&local_acl->a_entries[i], pACE);
3288 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003289 }
3290 }
3291 return size;
3292}
3293
Steve French50c2f752007-07-13 00:33:32 +00003294static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
3295 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003296{
3297 __u16 rc = 0; /* 0 = ACL converted ok */
3298
Steve Frenchff7feac2005-11-15 16:45:16 -08003299 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
3300 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003301 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00003302 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003303 /* Probably no need to le convert -1 on any arch but can not hurt */
3304 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00003305 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08003306 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesb6b38f72010-04-21 03:50:45 +00003307 /*cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id);*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003308 return rc;
3309}
3310
3311/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00003312static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
3313 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003314{
3315 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00003316 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
3317 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003318 int count;
3319 int i;
3320
Steve French790fe572007-07-07 19:25:05 +00003321 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003322 return 0;
3323
3324 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesb6b38f72010-04-21 03:50:45 +00003325 cFYI(1, "setting acl with %d entries from buf of length %d and "
Steve French63135e02007-07-17 17:34:02 +00003326 "version of %d",
Joe Perchesb6b38f72010-04-21 03:50:45 +00003327 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00003328 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003329 cFYI(1, "unknown POSIX ACL version %d",
3330 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003331 return 0;
3332 }
3333 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00003334 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08003335 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00003336 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08003337 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003338 else {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003339 cFYI(1, "unknown ACL type %d", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003340 return 0;
3341 }
Steve French50c2f752007-07-13 00:33:32 +00003342 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003343 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
3344 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00003345 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003346 /* ACE not converted */
3347 break;
3348 }
3349 }
Steve French790fe572007-07-07 19:25:05 +00003350 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003351 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
3352 rc += sizeof(struct cifs_posix_acl);
3353 /* BB add check to make sure ACL does not overflow SMB */
3354 }
3355 return rc;
3356}
3357
3358int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003359CIFSSMBGetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003360 const unsigned char *searchName,
3361 char *acl_inf, const int buflen, const int acl_type,
3362 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003363{
3364/* SMB_QUERY_POSIX_ACL */
3365 TRANSACTION2_QPI_REQ *pSMB = NULL;
3366 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3367 int rc = 0;
3368 int bytes_returned;
3369 int name_len;
3370 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00003371
Joe Perchesb6b38f72010-04-21 03:50:45 +00003372 cFYI(1, "In GetPosixACL (Unix) for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003373
3374queryAclRetry:
3375 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3376 (void **) &pSMBr);
3377 if (rc)
3378 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003379
Linus Torvalds1da177e2005-04-16 15:20:36 -07003380 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3381 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003382 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3383 searchName, PATH_MAX, nls_codepage,
3384 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003385 name_len++; /* trailing null */
3386 name_len *= 2;
3387 pSMB->FileName[name_len] = 0;
3388 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00003389 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003390 name_len = strnlen(searchName, PATH_MAX);
3391 name_len++; /* trailing null */
3392 strncpy(pSMB->FileName, searchName, name_len);
3393 }
3394
3395 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3396 pSMB->TotalDataCount = 0;
3397 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00003398 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003399 pSMB->MaxDataCount = cpu_to_le16(4000);
3400 pSMB->MaxSetupCount = 0;
3401 pSMB->Reserved = 0;
3402 pSMB->Flags = 0;
3403 pSMB->Timeout = 0;
3404 pSMB->Reserved2 = 0;
3405 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003406 offsetof(struct smb_com_transaction2_qpi_req,
3407 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003408 pSMB->DataCount = 0;
3409 pSMB->DataOffset = 0;
3410 pSMB->SetupCount = 1;
3411 pSMB->Reserved3 = 0;
3412 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3413 byte_count = params + 1 /* pad */ ;
3414 pSMB->TotalParameterCount = cpu_to_le16(params);
3415 pSMB->ParameterCount = pSMB->TotalParameterCount;
3416 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
3417 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003418 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003419 pSMB->ByteCount = cpu_to_le16(byte_count);
3420
3421 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3422 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003423 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003424 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003425 cFYI(1, "Send error in Query POSIX ACL = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003426 } else {
3427 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00003428
Linus Torvalds1da177e2005-04-16 15:20:36 -07003429 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003430 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003431 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003432 rc = -EIO; /* bad smb */
3433 else {
3434 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3435 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3436 rc = cifs_copy_posix_acl(acl_inf,
3437 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00003438 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003439 }
3440 }
3441 cifs_buf_release(pSMB);
3442 if (rc == -EAGAIN)
3443 goto queryAclRetry;
3444 return rc;
3445}
3446
3447int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003448CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003449 const unsigned char *fileName,
3450 const char *local_acl, const int buflen,
3451 const int acl_type,
3452 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003453{
3454 struct smb_com_transaction2_spi_req *pSMB = NULL;
3455 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3456 char *parm_data;
3457 int name_len;
3458 int rc = 0;
3459 int bytes_returned = 0;
3460 __u16 params, byte_count, data_count, param_offset, offset;
3461
Joe Perchesb6b38f72010-04-21 03:50:45 +00003462 cFYI(1, "In SetPosixACL (Unix) for path %s", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003463setAclRetry:
3464 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003465 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003466 if (rc)
3467 return rc;
3468 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3469 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003470 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
3471 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003472 name_len++; /* trailing null */
3473 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003474 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003475 name_len = strnlen(fileName, PATH_MAX);
3476 name_len++; /* trailing null */
3477 strncpy(pSMB->FileName, fileName, name_len);
3478 }
3479 params = 6 + name_len;
3480 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003481 /* BB find max SMB size from sess */
3482 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003483 pSMB->MaxSetupCount = 0;
3484 pSMB->Reserved = 0;
3485 pSMB->Flags = 0;
3486 pSMB->Timeout = 0;
3487 pSMB->Reserved2 = 0;
3488 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003489 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003490 offset = param_offset + params;
3491 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
3492 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3493
3494 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00003495 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003496
Steve French790fe572007-07-07 19:25:05 +00003497 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003498 rc = -EOPNOTSUPP;
3499 goto setACLerrorExit;
3500 }
3501 pSMB->DataOffset = cpu_to_le16(offset);
3502 pSMB->SetupCount = 1;
3503 pSMB->Reserved3 = 0;
3504 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3505 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
3506 byte_count = 3 /* pad */ + params + data_count;
3507 pSMB->DataCount = cpu_to_le16(data_count);
3508 pSMB->TotalDataCount = pSMB->DataCount;
3509 pSMB->ParameterCount = cpu_to_le16(params);
3510 pSMB->TotalParameterCount = pSMB->ParameterCount;
3511 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003512 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003513 pSMB->ByteCount = cpu_to_le16(byte_count);
3514 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003515 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003516 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003517 cFYI(1, "Set POSIX ACL returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003518
3519setACLerrorExit:
3520 cifs_buf_release(pSMB);
3521 if (rc == -EAGAIN)
3522 goto setAclRetry;
3523 return rc;
3524}
3525
Steve Frenchf654bac2005-04-28 22:41:04 -07003526/* BB fix tabs in this function FIXME BB */
3527int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003528CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00003529 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07003530{
Steve French50c2f752007-07-13 00:33:32 +00003531 int rc = 0;
3532 struct smb_t2_qfi_req *pSMB = NULL;
3533 struct smb_t2_qfi_rsp *pSMBr = NULL;
3534 int bytes_returned;
3535 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07003536
Joe Perchesb6b38f72010-04-21 03:50:45 +00003537 cFYI(1, "In GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00003538 if (tcon == NULL)
3539 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07003540
3541GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003542 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3543 (void **) &pSMBr);
3544 if (rc)
3545 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003546
Steve Frenchad7a2922008-02-07 23:25:02 +00003547 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003548 pSMB->t2.TotalDataCount = 0;
3549 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3550 /* BB find exact max data count below from sess structure BB */
3551 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3552 pSMB->t2.MaxSetupCount = 0;
3553 pSMB->t2.Reserved = 0;
3554 pSMB->t2.Flags = 0;
3555 pSMB->t2.Timeout = 0;
3556 pSMB->t2.Reserved2 = 0;
3557 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3558 Fid) - 4);
3559 pSMB->t2.DataCount = 0;
3560 pSMB->t2.DataOffset = 0;
3561 pSMB->t2.SetupCount = 1;
3562 pSMB->t2.Reserved3 = 0;
3563 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3564 byte_count = params + 1 /* pad */ ;
3565 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3566 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3567 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3568 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003569 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003570 inc_rfc1001_len(pSMB, byte_count);
Steve French790fe572007-07-07 19:25:05 +00003571 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003572
Steve French790fe572007-07-07 19:25:05 +00003573 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3574 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3575 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003576 cFYI(1, "error %d in GetExtAttr", rc);
Steve French790fe572007-07-07 19:25:05 +00003577 } else {
3578 /* decode response */
3579 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003580 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003581 if (rc || get_bcc(&pSMBr->hdr) < 2)
Steve French790fe572007-07-07 19:25:05 +00003582 /* If rc should we check for EOPNOSUPP and
3583 disable the srvino flag? or in caller? */
3584 rc = -EIO; /* bad smb */
3585 else {
3586 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3587 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3588 struct file_chattr_info *pfinfo;
3589 /* BB Do we need a cast or hash here ? */
3590 if (count != 16) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003591 cFYI(1, "Illegal size ret in GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00003592 rc = -EIO;
3593 goto GetExtAttrOut;
3594 }
3595 pfinfo = (struct file_chattr_info *)
3596 (data_offset + (char *) &pSMBr->hdr.Protocol);
3597 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003598 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003599 }
3600 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003601GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003602 cifs_buf_release(pSMB);
3603 if (rc == -EAGAIN)
3604 goto GetExtAttrRetry;
3605 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003606}
3607
Steve Frenchf654bac2005-04-28 22:41:04 -07003608#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003609
Jeff Layton79df1ba2010-12-06 12:52:08 -05003610#ifdef CONFIG_CIFS_ACL
3611/*
3612 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3613 * all NT TRANSACTS that we init here have total parm and data under about 400
3614 * bytes (to fit in small cifs buffer size), which is the case so far, it
3615 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3616 * returned setup area) and MaxParameterCount (returned parms size) must be set
3617 * by caller
3618 */
3619static int
3620smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French96daf2b2011-05-27 04:34:02 +00003621 const int parm_len, struct cifs_tcon *tcon,
Jeff Layton79df1ba2010-12-06 12:52:08 -05003622 void **ret_buf)
3623{
3624 int rc;
3625 __u32 temp_offset;
3626 struct smb_com_ntransact_req *pSMB;
3627
3628 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3629 (void **)&pSMB);
3630 if (rc)
3631 return rc;
3632 *ret_buf = (void *)pSMB;
3633 pSMB->Reserved = 0;
3634 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3635 pSMB->TotalDataCount = 0;
Jeff Laytonc974bef2011-10-11 06:41:32 -04003636 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003637 pSMB->ParameterCount = pSMB->TotalParameterCount;
3638 pSMB->DataCount = pSMB->TotalDataCount;
3639 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3640 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3641 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3642 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3643 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3644 pSMB->SubCommand = cpu_to_le16(sub_command);
3645 return 0;
3646}
3647
3648static int
3649validate_ntransact(char *buf, char **ppparm, char **ppdata,
3650 __u32 *pparmlen, __u32 *pdatalen)
3651{
3652 char *end_of_smb;
3653 __u32 data_count, data_offset, parm_count, parm_offset;
3654 struct smb_com_ntransact_rsp *pSMBr;
Jeff Layton820a8032011-05-04 08:05:26 -04003655 u16 bcc;
Jeff Layton79df1ba2010-12-06 12:52:08 -05003656
3657 *pdatalen = 0;
3658 *pparmlen = 0;
3659
3660 if (buf == NULL)
3661 return -EINVAL;
3662
3663 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3664
Jeff Layton820a8032011-05-04 08:05:26 -04003665 bcc = get_bcc(&pSMBr->hdr);
3666 end_of_smb = 2 /* sizeof byte count */ + bcc +
Jeff Layton79df1ba2010-12-06 12:52:08 -05003667 (char *)&pSMBr->ByteCount;
3668
3669 data_offset = le32_to_cpu(pSMBr->DataOffset);
3670 data_count = le32_to_cpu(pSMBr->DataCount);
3671 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3672 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3673
3674 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3675 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3676
3677 /* should we also check that parm and data areas do not overlap? */
3678 if (*ppparm > end_of_smb) {
3679 cFYI(1, "parms start after end of smb");
3680 return -EINVAL;
3681 } else if (parm_count + *ppparm > end_of_smb) {
3682 cFYI(1, "parm end after end of smb");
3683 return -EINVAL;
3684 } else if (*ppdata > end_of_smb) {
3685 cFYI(1, "data starts after end of smb");
3686 return -EINVAL;
3687 } else if (data_count + *ppdata > end_of_smb) {
3688 cFYI(1, "data %p + count %d (%p) past smb end %p start %p",
3689 *ppdata, data_count, (data_count + *ppdata),
3690 end_of_smb, pSMBr);
3691 return -EINVAL;
Jeff Layton820a8032011-05-04 08:05:26 -04003692 } else if (parm_count + data_count > bcc) {
Jeff Layton79df1ba2010-12-06 12:52:08 -05003693 cFYI(1, "parm count and data count larger than SMB");
3694 return -EINVAL;
3695 }
3696 *pdatalen = data_count;
3697 *pparmlen = parm_count;
3698 return 0;
3699}
3700
Steve French0a4b92c2006-01-12 15:44:21 -08003701/* Get Security Descriptor (by handle) from remote server for a file or dir */
3702int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003703CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003704 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003705{
3706 int rc = 0;
3707 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003708 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003709 struct kvec iov[1];
3710
Joe Perchesb6b38f72010-04-21 03:50:45 +00003711 cFYI(1, "GetCifsACL");
Steve French0a4b92c2006-01-12 15:44:21 -08003712
Steve French630f3f0c2007-10-25 21:17:17 +00003713 *pbuflen = 0;
3714 *acl_inf = NULL;
3715
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003716 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003717 8 /* parm len */, tcon, (void **) &pSMB);
3718 if (rc)
3719 return rc;
3720
3721 pSMB->MaxParameterCount = cpu_to_le32(4);
3722 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3723 pSMB->MaxSetupCount = 0;
3724 pSMB->Fid = fid; /* file handle always le */
3725 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3726 CIFS_ACL_DACL);
3727 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003728 inc_rfc1001_len(pSMB, 11);
Steve French0a4b92c2006-01-12 15:44:21 -08003729 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003730 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French0a4b92c2006-01-12 15:44:21 -08003731
Steve Frencha761ac52007-10-18 21:45:27 +00003732 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Jeff Layton77499812011-01-11 07:24:23 -05003733 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003734 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Steve French0a4b92c2006-01-12 15:44:21 -08003735 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003736 cFYI(1, "Send error in QuerySecDesc = %d", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08003737 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003738 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003739 __u32 parm_len;
3740 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003741 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003742 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003743
3744/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003745 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003746 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003747 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003748 goto qsec_out;
3749 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3750
Joe Perchesb6b38f72010-04-21 03:50:45 +00003751 cFYI(1, "smb %p parm %p data %p", pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08003752
3753 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3754 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003755 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003756 goto qsec_out;
3757 }
3758
3759/* BB check that data area is minimum length and as big as acl_len */
3760
Steve Frenchaf6f4612007-10-16 18:40:37 +00003761 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003762 if (acl_len != *pbuflen) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003763 cERROR(1, "acl length %d does not match %d",
3764 acl_len, *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003765 if (*pbuflen > acl_len)
3766 *pbuflen = acl_len;
3767 }
Steve French0a4b92c2006-01-12 15:44:21 -08003768
Steve French630f3f0c2007-10-25 21:17:17 +00003769 /* check if buffer is big enough for the acl
3770 header followed by the smallest SID */
3771 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3772 (*pbuflen >= 64 * 1024)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003773 cERROR(1, "bad acl length %d", *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003774 rc = -EINVAL;
3775 *pbuflen = 0;
3776 } else {
3777 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3778 if (*acl_inf == NULL) {
3779 *pbuflen = 0;
3780 rc = -ENOMEM;
3781 }
3782 memcpy(*acl_inf, pdata, *pbuflen);
3783 }
Steve French0a4b92c2006-01-12 15:44:21 -08003784 }
3785qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003786 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003787 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003788 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003789 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003790/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003791 return rc;
3792}
Steve French97837582007-12-31 07:47:21 +00003793
3794int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003795CIFSSMBSetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003796 struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
Steve French97837582007-12-31 07:47:21 +00003797{
3798 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3799 int rc = 0;
3800 int bytes_returned = 0;
3801 SET_SEC_DESC_REQ *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003802 void *pSMBr;
Steve French97837582007-12-31 07:47:21 +00003803
3804setCifsAclRetry:
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003805 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, &pSMBr);
Steve French97837582007-12-31 07:47:21 +00003806 if (rc)
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003807 return rc;
Steve French97837582007-12-31 07:47:21 +00003808
3809 pSMB->MaxSetupCount = 0;
3810 pSMB->Reserved = 0;
3811
3812 param_count = 8;
3813 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3814 data_count = acllen;
3815 data_offset = param_offset + param_count;
3816 byte_count = 3 /* pad */ + param_count;
3817
3818 pSMB->DataCount = cpu_to_le32(data_count);
3819 pSMB->TotalDataCount = pSMB->DataCount;
3820 pSMB->MaxParameterCount = cpu_to_le32(4);
3821 pSMB->MaxDataCount = cpu_to_le32(16384);
3822 pSMB->ParameterCount = cpu_to_le32(param_count);
3823 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3824 pSMB->TotalParameterCount = pSMB->ParameterCount;
3825 pSMB->DataOffset = cpu_to_le32(data_offset);
3826 pSMB->SetupCount = 0;
3827 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3828 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3829
3830 pSMB->Fid = fid; /* file handle always le */
3831 pSMB->Reserved2 = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003832 pSMB->AclFlags = cpu_to_le32(aclflag);
Steve French97837582007-12-31 07:47:21 +00003833
3834 if (pntsd && acllen) {
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003835 memcpy((char *)pSMBr + offsetof(struct smb_hdr, Protocol) +
3836 data_offset, pntsd, acllen);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003837 inc_rfc1001_len(pSMB, byte_count + data_count);
Steve French97837582007-12-31 07:47:21 +00003838 } else
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003839 inc_rfc1001_len(pSMB, byte_count);
Steve French97837582007-12-31 07:47:21 +00003840
3841 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3842 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3843
Joe Perchesb6b38f72010-04-21 03:50:45 +00003844 cFYI(1, "SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00003845 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003846 cFYI(1, "Set CIFS ACL returned %d", rc);
Steve French97837582007-12-31 07:47:21 +00003847 cifs_buf_release(pSMB);
3848
3849 if (rc == -EAGAIN)
3850 goto setCifsAclRetry;
3851
3852 return (rc);
3853}
3854
Jeff Layton79df1ba2010-12-06 12:52:08 -05003855#endif /* CONFIG_CIFS_ACL */
Steve French0a4b92c2006-01-12 15:44:21 -08003856
Steve French6b8edfe2005-08-23 20:26:03 -07003857/* Legacy Query Path Information call for lookup to old servers such
3858 as Win9x/WinME */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003859int
3860SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon,
3861 const char *search_name, FILE_ALL_INFO *data,
3862 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003863{
Steve Frenchad7a2922008-02-07 23:25:02 +00003864 QUERY_INFORMATION_REQ *pSMB;
3865 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003866 int rc = 0;
3867 int bytes_returned;
3868 int name_len;
3869
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003870 cFYI(1, "In SMBQPath path %s", search_name);
Steve French6b8edfe2005-08-23 20:26:03 -07003871QInfRetry:
3872 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003873 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003874 if (rc)
3875 return rc;
3876
3877 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3878 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003879 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003880 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06003881 remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003882 name_len++; /* trailing null */
3883 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003884 } else {
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003885 name_len = strnlen(search_name, PATH_MAX);
Steve French6b8edfe2005-08-23 20:26:03 -07003886 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003887 strncpy(pSMB->FileName, search_name, name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07003888 }
3889 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003890 name_len++; /* account for buffer type byte */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003891 inc_rfc1001_len(pSMB, (__u16)name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07003892 pSMB->ByteCount = cpu_to_le16(name_len);
3893
3894 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003895 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003896 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003897 cFYI(1, "Send error in QueryInfo = %d", rc);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003898 } else if (data) {
Steve French1bd5bbc2006-09-28 03:35:57 +00003899 struct timespec ts;
3900 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00003901
3902 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003903 /* BB FIXME - add time zone adjustment BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003904 memset(data, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003905 ts.tv_nsec = 0;
3906 ts.tv_sec = time;
3907 /* decode time fields */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003908 data->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
3909 data->LastWriteTime = data->ChangeTime;
3910 data->LastAccessTime = 0;
3911 data->AllocationSize =
Steve French70ca7342005-09-22 16:32:06 -07003912 cpu_to_le64(le32_to_cpu(pSMBr->size));
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003913 data->EndOfFile = data->AllocationSize;
3914 data->Attributes =
Steve French70ca7342005-09-22 16:32:06 -07003915 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003916 } else
3917 rc = -EIO; /* bad buffer passed in */
3918
3919 cifs_buf_release(pSMB);
3920
3921 if (rc == -EAGAIN)
3922 goto QInfRetry;
3923
3924 return rc;
3925}
3926
Jeff Laytonbcd53572010-02-12 07:44:16 -05003927int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003928CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonbcd53572010-02-12 07:44:16 -05003929 u16 netfid, FILE_ALL_INFO *pFindData)
3930{
3931 struct smb_t2_qfi_req *pSMB = NULL;
3932 struct smb_t2_qfi_rsp *pSMBr = NULL;
3933 int rc = 0;
3934 int bytes_returned;
3935 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07003936
Jeff Laytonbcd53572010-02-12 07:44:16 -05003937QFileInfoRetry:
3938 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3939 (void **) &pSMBr);
3940 if (rc)
3941 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07003942
Jeff Laytonbcd53572010-02-12 07:44:16 -05003943 params = 2 /* level */ + 2 /* fid */;
3944 pSMB->t2.TotalDataCount = 0;
3945 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3946 /* BB find exact max data count below from sess structure BB */
3947 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3948 pSMB->t2.MaxSetupCount = 0;
3949 pSMB->t2.Reserved = 0;
3950 pSMB->t2.Flags = 0;
3951 pSMB->t2.Timeout = 0;
3952 pSMB->t2.Reserved2 = 0;
3953 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3954 Fid) - 4);
3955 pSMB->t2.DataCount = 0;
3956 pSMB->t2.DataOffset = 0;
3957 pSMB->t2.SetupCount = 1;
3958 pSMB->t2.Reserved3 = 0;
3959 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3960 byte_count = params + 1 /* pad */ ;
3961 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3962 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3963 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3964 pSMB->Pad = 0;
3965 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003966 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003967
3968 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3969 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3970 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00003971 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003972 } else { /* decode response */
3973 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3974
3975 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3976 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04003977 else if (get_bcc(&pSMBr->hdr) < 40)
Jeff Laytonbcd53572010-02-12 07:44:16 -05003978 rc = -EIO; /* bad smb */
3979 else if (pFindData) {
3980 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3981 memcpy((char *) pFindData,
3982 (char *) &pSMBr->hdr.Protocol +
3983 data_offset, sizeof(FILE_ALL_INFO));
3984 } else
3985 rc = -ENOMEM;
3986 }
3987 cifs_buf_release(pSMB);
3988 if (rc == -EAGAIN)
3989 goto QFileInfoRetry;
3990
3991 return rc;
3992}
Steve French6b8edfe2005-08-23 20:26:03 -07003993
Linus Torvalds1da177e2005-04-16 15:20:36 -07003994int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003995CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003996 const char *search_name, FILE_ALL_INFO *data,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003997 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003998 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003999{
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004000 /* level 263 SMB_QUERY_FILE_ALL_INFO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004001 TRANSACTION2_QPI_REQ *pSMB = NULL;
4002 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4003 int rc = 0;
4004 int bytes_returned;
4005 int name_len;
4006 __u16 params, byte_count;
4007
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004008 /* cFYI(1, "In QPathInfo path %s", search_name); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004009QPathInfoRetry:
4010 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4011 (void **) &pSMBr);
4012 if (rc)
4013 return rc;
4014
4015 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4016 name_len =
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004017 cifsConvertToUTF16((__le16 *) pSMB->FileName, search_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06004018 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004019 name_len++; /* trailing null */
4020 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004021 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004022 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004023 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004024 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004025 }
4026
Steve French50c2f752007-07-13 00:33:32 +00004027 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004028 pSMB->TotalDataCount = 0;
4029 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004030 /* BB find exact max SMB PDU from sess structure BB */
4031 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004032 pSMB->MaxSetupCount = 0;
4033 pSMB->Reserved = 0;
4034 pSMB->Flags = 0;
4035 pSMB->Timeout = 0;
4036 pSMB->Reserved2 = 0;
4037 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004038 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004039 pSMB->DataCount = 0;
4040 pSMB->DataOffset = 0;
4041 pSMB->SetupCount = 1;
4042 pSMB->Reserved3 = 0;
4043 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4044 byte_count = params + 1 /* pad */ ;
4045 pSMB->TotalParameterCount = cpu_to_le16(params);
4046 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00004047 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004048 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
4049 else
4050 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004051 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004052 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004053 pSMB->ByteCount = cpu_to_le16(byte_count);
4054
4055 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4056 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4057 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004058 cFYI(1, "Send error in QPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004059 } else { /* decode response */
4060 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4061
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004062 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4063 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004064 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004065 rc = -EIO; /* bad smb */
Jeff Layton820a8032011-05-04 08:05:26 -04004066 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
Steve French50c2f752007-07-13 00:33:32 +00004067 rc = -EIO; /* 24 or 26 expected but we do not read
4068 last field */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004069 else if (data) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004070 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004071 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00004072
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004073 /*
4074 * On legacy responses we do not read the last field,
4075 * EAsize, fortunately since it varies by subdialect and
4076 * also note it differs on Set vs Get, ie two bytes or 4
4077 * bytes depending but we don't care here.
4078 */
Steve Frenchad7a2922008-02-07 23:25:02 +00004079 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004080 size = sizeof(FILE_INFO_STANDARD);
4081 else
4082 size = sizeof(FILE_ALL_INFO);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004083 memcpy((char *) data, (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004084 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004085 } else
4086 rc = -ENOMEM;
4087 }
4088 cifs_buf_release(pSMB);
4089 if (rc == -EAGAIN)
4090 goto QPathInfoRetry;
4091
4092 return rc;
4093}
4094
4095int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004096CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004097 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
4098{
4099 struct smb_t2_qfi_req *pSMB = NULL;
4100 struct smb_t2_qfi_rsp *pSMBr = NULL;
4101 int rc = 0;
4102 int bytes_returned;
4103 __u16 params, byte_count;
4104
4105UnixQFileInfoRetry:
4106 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4107 (void **) &pSMBr);
4108 if (rc)
4109 return rc;
4110
4111 params = 2 /* level */ + 2 /* fid */;
4112 pSMB->t2.TotalDataCount = 0;
4113 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4114 /* BB find exact max data count below from sess structure BB */
4115 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4116 pSMB->t2.MaxSetupCount = 0;
4117 pSMB->t2.Reserved = 0;
4118 pSMB->t2.Flags = 0;
4119 pSMB->t2.Timeout = 0;
4120 pSMB->t2.Reserved2 = 0;
4121 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4122 Fid) - 4);
4123 pSMB->t2.DataCount = 0;
4124 pSMB->t2.DataOffset = 0;
4125 pSMB->t2.SetupCount = 1;
4126 pSMB->t2.Reserved3 = 0;
4127 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4128 byte_count = params + 1 /* pad */ ;
4129 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4130 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4131 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4132 pSMB->Pad = 0;
4133 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004134 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004135
4136 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4137 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4138 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00004139 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004140 } else { /* decode response */
4141 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4142
Jeff Layton820a8032011-05-04 08:05:26 -04004143 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004144 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response. "
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004145 "Unix Extensions can be disabled on mount "
Steve Frenchf19159d2010-04-21 04:12:10 +00004146 "by specifying the nosfu mount option.");
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004147 rc = -EIO; /* bad smb */
4148 } else {
4149 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4150 memcpy((char *) pFindData,
4151 (char *) &pSMBr->hdr.Protocol +
4152 data_offset,
4153 sizeof(FILE_UNIX_BASIC_INFO));
4154 }
4155 }
4156
4157 cifs_buf_release(pSMB);
4158 if (rc == -EAGAIN)
4159 goto UnixQFileInfoRetry;
4160
4161 return rc;
4162}
4163
4164int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004165CIFSSMBUnixQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004166 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00004167 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07004168 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004169{
4170/* SMB_QUERY_FILE_UNIX_BASIC */
4171 TRANSACTION2_QPI_REQ *pSMB = NULL;
4172 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4173 int rc = 0;
4174 int bytes_returned = 0;
4175 int name_len;
4176 __u16 params, byte_count;
4177
Joe Perchesb6b38f72010-04-21 03:50:45 +00004178 cFYI(1, "In QPathInfo (Unix) the path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004179UnixQPathInfoRetry:
4180 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4181 (void **) &pSMBr);
4182 if (rc)
4183 return rc;
4184
4185 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4186 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004187 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4188 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004189 name_len++; /* trailing null */
4190 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004191 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004192 name_len = strnlen(searchName, PATH_MAX);
4193 name_len++; /* trailing null */
4194 strncpy(pSMB->FileName, searchName, name_len);
4195 }
4196
Steve French50c2f752007-07-13 00:33:32 +00004197 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004198 pSMB->TotalDataCount = 0;
4199 pSMB->MaxParameterCount = cpu_to_le16(2);
4200 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00004201 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004202 pSMB->MaxSetupCount = 0;
4203 pSMB->Reserved = 0;
4204 pSMB->Flags = 0;
4205 pSMB->Timeout = 0;
4206 pSMB->Reserved2 = 0;
4207 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004208 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004209 pSMB->DataCount = 0;
4210 pSMB->DataOffset = 0;
4211 pSMB->SetupCount = 1;
4212 pSMB->Reserved3 = 0;
4213 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4214 byte_count = params + 1 /* pad */ ;
4215 pSMB->TotalParameterCount = cpu_to_le16(params);
4216 pSMB->ParameterCount = pSMB->TotalParameterCount;
4217 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4218 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004219 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004220 pSMB->ByteCount = cpu_to_le16(byte_count);
4221
4222 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4223 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4224 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004225 cFYI(1, "Send error in QPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004226 } else { /* decode response */
4227 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4228
Jeff Layton820a8032011-05-04 08:05:26 -04004229 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004230 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response. "
Steve French1e71f252007-09-20 15:30:07 +00004231 "Unix Extensions can be disabled on mount "
Joe Perchesb6b38f72010-04-21 03:50:45 +00004232 "by specifying the nosfu mount option.");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004233 rc = -EIO; /* bad smb */
4234 } else {
4235 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4236 memcpy((char *) pFindData,
4237 (char *) &pSMBr->hdr.Protocol +
4238 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00004239 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004240 }
4241 }
4242 cifs_buf_release(pSMB);
4243 if (rc == -EAGAIN)
4244 goto UnixQPathInfoRetry;
4245
4246 return rc;
4247}
4248
Linus Torvalds1da177e2005-04-16 15:20:36 -07004249/* xid, tcon, searchName and codepage are input parms, rest are returned */
4250int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004251CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004252 const char *searchName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004253 const struct nls_table *nls_codepage,
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004254 __u16 *pnetfid, __u16 search_flags,
Steve French50c2f752007-07-13 00:33:32 +00004255 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004256{
4257/* level 257 SMB_ */
4258 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
4259 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004260 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004261 int rc = 0;
4262 int bytes_returned = 0;
4263 int name_len;
4264 __u16 params, byte_count;
4265
Joe Perchesb6b38f72010-04-21 03:50:45 +00004266 cFYI(1, "In FindFirst for %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004267
4268findFirstRetry:
4269 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4270 (void **) &pSMBr);
4271 if (rc)
4272 return rc;
4273
4274 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4275 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004276 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4277 PATH_MAX, nls_codepage, remap);
Steve French737b7582005-04-28 22:41:06 -07004278 /* We can not add the asterik earlier in case
4279 it got remapped to 0xF03A as if it were part of the
4280 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004281 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07004282 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07004283 pSMB->FileName[name_len+1] = 0;
4284 pSMB->FileName[name_len+2] = '*';
4285 pSMB->FileName[name_len+3] = 0;
4286 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004287 pSMB->FileName[name_len] = 0; /* null terminate just in case */
4288 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07004289 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004290 } else { /* BB add check for overrun of SMB buf BB */
4291 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004292/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00004293 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004294 free buffer exit; BB */
4295 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07004296 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07004297 pSMB->FileName[name_len+1] = '*';
4298 pSMB->FileName[name_len+2] = 0;
4299 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004300 }
4301
4302 params = 12 + name_len /* includes null */ ;
4303 pSMB->TotalDataCount = 0; /* no EAs */
4304 pSMB->MaxParameterCount = cpu_to_le16(10);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004305 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004306 pSMB->MaxSetupCount = 0;
4307 pSMB->Reserved = 0;
4308 pSMB->Flags = 0;
4309 pSMB->Timeout = 0;
4310 pSMB->Reserved2 = 0;
4311 byte_count = params + 1 /* pad */ ;
4312 pSMB->TotalParameterCount = cpu_to_le16(params);
4313 pSMB->ParameterCount = pSMB->TotalParameterCount;
4314 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00004315 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
4316 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004317 pSMB->DataCount = 0;
4318 pSMB->DataOffset = 0;
4319 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
4320 pSMB->Reserved3 = 0;
4321 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
4322 pSMB->SearchAttributes =
4323 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
4324 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00004325 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004326 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004327 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4328
4329 /* BB what should we set StorageType to? Does it matter? BB */
4330 pSMB->SearchStorageType = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004331 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004332 pSMB->ByteCount = cpu_to_le16(byte_count);
4333
4334 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4335 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004336 cifs_stats_inc(&tcon->stats.cifs_stats.num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004337
Steve French88274812006-03-09 22:21:45 +00004338 if (rc) {/* BB add logic to retry regular search if Unix search
4339 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004340 /* BB Add code to handle unsupported level rc */
Joe Perchesb6b38f72010-04-21 03:50:45 +00004341 cFYI(1, "Error in FindFirst = %d", rc);
Steve French1982c342005-08-17 12:38:22 -07004342
Steve French88274812006-03-09 22:21:45 +00004343 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004344
4345 /* BB eventually could optimize out free and realloc of buf */
4346 /* for this case */
4347 if (rc == -EAGAIN)
4348 goto findFirstRetry;
4349 } else { /* decode response */
4350 /* BB remember to free buffer if error BB */
4351 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00004352 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004353 unsigned int lnoff;
4354
Linus Torvalds1da177e2005-04-16 15:20:36 -07004355 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004356 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004357 else
Steve French4b18f2a2008-04-29 00:06:05 +00004358 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004359
4360 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004361 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00004362 psrch_inf->srch_entries_start =
4363 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004364 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004365 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
4366 le16_to_cpu(pSMBr->t2.ParameterOffset));
4367
Steve French790fe572007-07-07 19:25:05 +00004368 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004369 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004370 else
Steve French4b18f2a2008-04-29 00:06:05 +00004371 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004372
Steve French50c2f752007-07-13 00:33:32 +00004373 psrch_inf->entries_in_buffer =
4374 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00004375 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004376 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004377 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004378 if (CIFSMaxBufSize < lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004379 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00004380 psrch_inf->last_entry = NULL;
4381 return rc;
4382 }
4383
Steve French0752f152008-10-07 20:03:33 +00004384 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00004385 lnoff;
4386
Linus Torvalds1da177e2005-04-16 15:20:36 -07004387 *pnetfid = parms->SearchHandle;
4388 } else {
4389 cifs_buf_release(pSMB);
4390 }
4391 }
4392
4393 return rc;
4394}
4395
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004396int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
4397 __u16 searchHandle, __u16 search_flags,
4398 struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004399{
4400 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
4401 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004402 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004403 char *response_data;
4404 int rc = 0;
Jeff Layton9438fab2011-08-23 07:21:28 -04004405 int bytes_returned;
4406 unsigned int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004407 __u16 params, byte_count;
4408
Joe Perchesb6b38f72010-04-21 03:50:45 +00004409 cFYI(1, "In FindNext");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004410
Steve French4b18f2a2008-04-29 00:06:05 +00004411 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004412 return -ENOENT;
4413
4414 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4415 (void **) &pSMBr);
4416 if (rc)
4417 return rc;
4418
Steve French50c2f752007-07-13 00:33:32 +00004419 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004420 byte_count = 0;
4421 pSMB->TotalDataCount = 0; /* no EAs */
4422 pSMB->MaxParameterCount = cpu_to_le16(8);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004423 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004424 pSMB->MaxSetupCount = 0;
4425 pSMB->Reserved = 0;
4426 pSMB->Flags = 0;
4427 pSMB->Timeout = 0;
4428 pSMB->Reserved2 = 0;
4429 pSMB->ParameterOffset = cpu_to_le16(
4430 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
4431 pSMB->DataCount = 0;
4432 pSMB->DataOffset = 0;
4433 pSMB->SetupCount = 1;
4434 pSMB->Reserved3 = 0;
4435 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
4436 pSMB->SearchHandle = searchHandle; /* always kept as le */
4437 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00004438 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004439 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4440 pSMB->ResumeKey = psrch_inf->resume_key;
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004441 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004442
4443 name_len = psrch_inf->resume_name_len;
4444 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00004445 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004446 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
4447 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07004448 /* 14 byte parm len above enough for 2 byte null terminator */
4449 pSMB->ResumeFileName[name_len] = 0;
4450 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004451 } else {
4452 rc = -EINVAL;
4453 goto FNext2_err_exit;
4454 }
4455 byte_count = params + 1 /* pad */ ;
4456 pSMB->TotalParameterCount = cpu_to_le16(params);
4457 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004458 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004459 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004460
Linus Torvalds1da177e2005-04-16 15:20:36 -07004461 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4462 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004463 cifs_stats_inc(&tcon->stats.cifs_stats.num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004464 if (rc) {
4465 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00004466 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07004467 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00004468 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004469 } else
Joe Perchesb6b38f72010-04-21 03:50:45 +00004470 cFYI(1, "FindNext returned = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004471 } else { /* decode response */
4472 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00004473
Steve French790fe572007-07-07 19:25:05 +00004474 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004475 unsigned int lnoff;
4476
Linus Torvalds1da177e2005-04-16 15:20:36 -07004477 /* BB fixme add lock for file (srch_info) struct here */
4478 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004479 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004480 else
Steve French4b18f2a2008-04-29 00:06:05 +00004481 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004482 response_data = (char *) &pSMBr->hdr.Protocol +
4483 le16_to_cpu(pSMBr->t2.ParameterOffset);
4484 parms = (T2_FNEXT_RSP_PARMS *)response_data;
4485 response_data = (char *)&pSMBr->hdr.Protocol +
4486 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00004487 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00004488 cifs_small_buf_release(
4489 psrch_inf->ntwrk_buf_start);
4490 else
4491 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004492 psrch_inf->srch_entries_start = response_data;
4493 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004494 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00004495 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004496 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004497 else
Steve French4b18f2a2008-04-29 00:06:05 +00004498 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00004499 psrch_inf->entries_in_buffer =
4500 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004501 psrch_inf->index_of_last_entry +=
4502 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004503 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004504 if (CIFSMaxBufSize < lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004505 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00004506 psrch_inf->last_entry = NULL;
4507 return rc;
4508 } else
4509 psrch_inf->last_entry =
4510 psrch_inf->srch_entries_start + lnoff;
4511
Joe Perchesb6b38f72010-04-21 03:50:45 +00004512/* cFYI(1, "fnxt2 entries in buf %d index_of_last %d",
4513 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004514
4515 /* BB fixme add unlock here */
4516 }
4517
4518 }
4519
4520 /* BB On error, should we leave previous search buf (and count and
4521 last entry fields) intact or free the previous one? */
4522
4523 /* Note: On -EAGAIN error only caller can retry on handle based calls
4524 since file handle passed in no longer valid */
4525FNext2_err_exit:
4526 if (rc != 0)
4527 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004528 return rc;
4529}
4530
4531int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004532CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004533 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004534{
4535 int rc = 0;
4536 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004537
Joe Perchesb6b38f72010-04-21 03:50:45 +00004538 cFYI(1, "In CIFSSMBFindClose");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004539 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
4540
4541 /* no sense returning error if session restarted
4542 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00004543 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004544 return 0;
4545 if (rc)
4546 return rc;
4547
Linus Torvalds1da177e2005-04-16 15:20:36 -07004548 pSMB->FileID = searchHandle;
4549 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04004550 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004551 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00004552 cERROR(1, "Send error in FindClose = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00004553
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004554 cifs_stats_inc(&tcon->stats.cifs_stats.num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004555
4556 /* Since session is dead, search handle closed on server already */
4557 if (rc == -EAGAIN)
4558 rc = 0;
4559
4560 return rc;
4561}
4562
Linus Torvalds1da177e2005-04-16 15:20:36 -07004563int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004564CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004565 const char *search_name, __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00004566 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004567{
4568 int rc = 0;
4569 TRANSACTION2_QPI_REQ *pSMB = NULL;
4570 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4571 int name_len, bytes_returned;
4572 __u16 params, byte_count;
4573
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004574 cFYI(1, "In GetSrvInodeNum for %s", search_name);
Steve French790fe572007-07-07 19:25:05 +00004575 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00004576 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004577
4578GetInodeNumberRetry:
4579 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004580 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004581 if (rc)
4582 return rc;
4583
Linus Torvalds1da177e2005-04-16 15:20:36 -07004584 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4585 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004586 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004587 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004588 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004589 name_len++; /* trailing null */
4590 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004591 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004592 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004593 name_len++; /* trailing null */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004594 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004595 }
4596
4597 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4598 pSMB->TotalDataCount = 0;
4599 pSMB->MaxParameterCount = cpu_to_le16(2);
4600 /* BB find exact max data count below from sess structure BB */
4601 pSMB->MaxDataCount = cpu_to_le16(4000);
4602 pSMB->MaxSetupCount = 0;
4603 pSMB->Reserved = 0;
4604 pSMB->Flags = 0;
4605 pSMB->Timeout = 0;
4606 pSMB->Reserved2 = 0;
4607 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004608 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004609 pSMB->DataCount = 0;
4610 pSMB->DataOffset = 0;
4611 pSMB->SetupCount = 1;
4612 pSMB->Reserved3 = 0;
4613 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4614 byte_count = params + 1 /* pad */ ;
4615 pSMB->TotalParameterCount = cpu_to_le16(params);
4616 pSMB->ParameterCount = pSMB->TotalParameterCount;
4617 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4618 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004619 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004620 pSMB->ByteCount = cpu_to_le16(byte_count);
4621
4622 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4623 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4624 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004625 cFYI(1, "error %d in QueryInternalInfo", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004626 } else {
4627 /* decode response */
4628 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004629 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04004630 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004631 /* If rc should we check for EOPNOSUPP and
4632 disable the srvino flag? or in caller? */
4633 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00004634 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004635 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4636 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00004637 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004638 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00004639 if (count < 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004640 cFYI(1, "Illegal size ret in QryIntrnlInf");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004641 rc = -EIO;
4642 goto GetInodeNumOut;
4643 }
4644 pfinfo = (struct file_internal_info *)
4645 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00004646 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004647 }
4648 }
4649GetInodeNumOut:
4650 cifs_buf_release(pSMB);
4651 if (rc == -EAGAIN)
4652 goto GetInodeNumberRetry;
4653 return rc;
4654}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004655
Igor Mammedovfec45852008-05-16 13:06:30 +04004656/* parses DFS refferal V3 structure
4657 * caller is responsible for freeing target_nodes
4658 * returns:
4659 * on success - 0
4660 * on failure - errno
4661 */
4662static int
Steve Frencha1fe78f2008-05-16 18:48:38 +00004663parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
Igor Mammedovfec45852008-05-16 13:06:30 +04004664 unsigned int *num_of_nodes,
4665 struct dfs_info3_param **target_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004666 const struct nls_table *nls_codepage, int remap,
4667 const char *searchName)
Igor Mammedovfec45852008-05-16 13:06:30 +04004668{
4669 int i, rc = 0;
4670 char *data_end;
4671 bool is_unicode;
4672 struct dfs_referral_level_3 *ref;
4673
Harvey Harrison5ca33c62008-07-23 17:45:58 -07004674 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4675 is_unicode = true;
4676 else
4677 is_unicode = false;
Igor Mammedovfec45852008-05-16 13:06:30 +04004678 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
4679
4680 if (*num_of_nodes < 1) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004681 cERROR(1, "num_referrals: must be at least > 0,"
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004682 "but we get num_referrals = %d", *num_of_nodes);
Igor Mammedovfec45852008-05-16 13:06:30 +04004683 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004684 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004685 }
4686
4687 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
Al Viro1d92cfd2008-06-02 10:59:02 +01004688 if (ref->VersionNumber != cpu_to_le16(3)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004689 cERROR(1, "Referrals of V%d version are not supported,"
4690 "should be V3", le16_to_cpu(ref->VersionNumber));
Igor Mammedovfec45852008-05-16 13:06:30 +04004691 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004692 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004693 }
4694
4695 /* get the upper boundary of the resp buffer */
4696 data_end = (char *)(&(pSMBr->PathConsumed)) +
4697 le16_to_cpu(pSMBr->t2.DataCount);
4698
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004699 cFYI(1, "num_referrals: %d dfs flags: 0x%x ...",
Igor Mammedovfec45852008-05-16 13:06:30 +04004700 *num_of_nodes,
Joe Perchesb6b38f72010-04-21 03:50:45 +00004701 le32_to_cpu(pSMBr->DFSFlags));
Igor Mammedovfec45852008-05-16 13:06:30 +04004702
4703 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
4704 *num_of_nodes, GFP_KERNEL);
4705 if (*target_nodes == NULL) {
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004706 cERROR(1, "Failed to allocate buffer for target_nodes");
Igor Mammedovfec45852008-05-16 13:06:30 +04004707 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004708 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004709 }
4710
Daniel Mack3ad2f3f2010-02-03 08:01:28 +08004711 /* collect necessary data from referrals */
Igor Mammedovfec45852008-05-16 13:06:30 +04004712 for (i = 0; i < *num_of_nodes; i++) {
4713 char *temp;
4714 int max_len;
4715 struct dfs_info3_param *node = (*target_nodes)+i;
4716
Steve French0e0d2cf2009-05-01 05:27:32 +00004717 node->flags = le32_to_cpu(pSMBr->DFSFlags);
Igor Mammedov2c556082008-10-23 13:58:42 +04004718 if (is_unicode) {
Jeff Layton331c3132008-12-17 06:31:53 -05004719 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4720 GFP_KERNEL);
Steve French2920ee22009-08-31 15:27:26 +00004721 if (tmp == NULL) {
4722 rc = -ENOMEM;
4723 goto parse_DFS_referrals_exit;
4724 }
Steve Frenchacbbb762012-01-18 22:32:33 -06004725 cifsConvertToUTF16((__le16 *) tmp, searchName,
4726 PATH_MAX, nls_codepage, remap);
4727 node->path_consumed = cifs_utf16_bytes(tmp,
Jeff Layton69f801f2009-04-30 06:46:32 -04004728 le16_to_cpu(pSMBr->PathConsumed),
Igor Mammedov2c556082008-10-23 13:58:42 +04004729 nls_codepage);
4730 kfree(tmp);
4731 } else
4732 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4733
Igor Mammedovfec45852008-05-16 13:06:30 +04004734 node->server_type = le16_to_cpu(ref->ServerType);
4735 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4736
4737 /* copy DfsPath */
4738 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4739 max_len = data_end - temp;
Steve Frenchacbbb762012-01-18 22:32:33 -06004740 node->path_name = cifs_strndup_from_utf16(temp, max_len,
4741 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004742 if (!node->path_name) {
4743 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004744 goto parse_DFS_referrals_exit;
Jeff Layton066ce682009-04-30 07:16:14 -04004745 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004746
4747 /* copy link target UNC */
4748 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4749 max_len = data_end - temp;
Steve Frenchacbbb762012-01-18 22:32:33 -06004750 node->node_name = cifs_strndup_from_utf16(temp, max_len,
4751 is_unicode, nls_codepage);
Stefan Metzmacherd8f27992012-05-04 00:19:28 +02004752 if (!node->node_name) {
Jeff Laytond8e2f532009-05-14 07:46:59 -04004753 rc = -ENOMEM;
Stefan Metzmacherd8f27992012-05-04 00:19:28 +02004754 goto parse_DFS_referrals_exit;
4755 }
4756
4757 ref++;
Igor Mammedovfec45852008-05-16 13:06:30 +04004758 }
4759
Steve Frencha1fe78f2008-05-16 18:48:38 +00004760parse_DFS_referrals_exit:
Igor Mammedovfec45852008-05-16 13:06:30 +04004761 if (rc) {
4762 free_dfs_info_array(*target_nodes, *num_of_nodes);
4763 *target_nodes = NULL;
4764 *num_of_nodes = 0;
4765 }
4766 return rc;
4767}
4768
Linus Torvalds1da177e2005-04-16 15:20:36 -07004769int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004770CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004771 const char *search_name, struct dfs_info3_param **target_nodes,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004772 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004773 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004774{
4775/* TRANS2_GET_DFS_REFERRAL */
4776 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4777 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004778 int rc = 0;
4779 int bytes_returned;
4780 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004781 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004782 *num_of_nodes = 0;
4783 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004784
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004785 cFYI(1, "In GetDFSRefer the path %s", search_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004786 if (ses == NULL)
4787 return -ENODEV;
4788getDFSRetry:
4789 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4790 (void **) &pSMBr);
4791 if (rc)
4792 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004793
4794 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004795 but should never be null here anyway */
Pavel Shilovsky88257362012-05-23 14:01:59 +04004796 pSMB->hdr.Mid = get_next_mid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004797 pSMB->hdr.Tid = ses->ipc_tid;
4798 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004799 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004800 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004801 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004802 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004803
4804 if (ses->capabilities & CAP_UNICODE) {
4805 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4806 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004807 cifsConvertToUTF16((__le16 *) pSMB->RequestFileName,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004808 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004809 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004810 name_len++; /* trailing null */
4811 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004812 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004813 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004814 name_len++; /* trailing null */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004815 strncpy(pSMB->RequestFileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004816 }
4817
Steve French790fe572007-07-07 19:25:05 +00004818 if (ses->server) {
Steve French96daf2b2011-05-27 04:34:02 +00004819 if (ses->server->sec_mode &
Steve French1a4e15a2006-10-12 21:33:51 +00004820 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4821 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4822 }
4823
Steve French50c2f752007-07-13 00:33:32 +00004824 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004825
Linus Torvalds1da177e2005-04-16 15:20:36 -07004826 params = 2 /* level */ + name_len /*includes null */ ;
4827 pSMB->TotalDataCount = 0;
4828 pSMB->DataCount = 0;
4829 pSMB->DataOffset = 0;
4830 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004831 /* BB find exact max SMB PDU from sess structure BB */
4832 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004833 pSMB->MaxSetupCount = 0;
4834 pSMB->Reserved = 0;
4835 pSMB->Flags = 0;
4836 pSMB->Timeout = 0;
4837 pSMB->Reserved2 = 0;
4838 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004839 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004840 pSMB->SetupCount = 1;
4841 pSMB->Reserved3 = 0;
4842 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4843 byte_count = params + 3 /* pad */ ;
4844 pSMB->ParameterCount = cpu_to_le16(params);
4845 pSMB->TotalParameterCount = pSMB->ParameterCount;
4846 pSMB->MaxReferralLevel = cpu_to_le16(3);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004847 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004848 pSMB->ByteCount = cpu_to_le16(byte_count);
4849
4850 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4851 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4852 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004853 cFYI(1, "Send error in GetDFSRefer = %d", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004854 goto GetDFSRefExit;
4855 }
4856 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004857
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004858 /* BB Also check if enough total bytes returned? */
Jeff Layton820a8032011-05-04 08:05:26 -04004859 if (rc || get_bcc(&pSMBr->hdr) < 17) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004860 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004861 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004862 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004863
Joe Perchesb6b38f72010-04-21 03:50:45 +00004864 cFYI(1, "Decoding GetDFSRefer response BCC: %d Offset %d",
Jeff Layton820a8032011-05-04 08:05:26 -04004865 get_bcc(&pSMBr->hdr),
Joe Perchesb6b38f72010-04-21 03:50:45 +00004866 le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04004867
4868 /* parse returned result into more usable form */
Steve Frencha1fe78f2008-05-16 18:48:38 +00004869 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004870 target_nodes, nls_codepage, remap,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004871 search_name);
Igor Mammedovfec45852008-05-16 13:06:30 +04004872
Linus Torvalds1da177e2005-04-16 15:20:36 -07004873GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004874 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004875
4876 if (rc == -EAGAIN)
4877 goto getDFSRetry;
4878
4879 return rc;
4880}
4881
Steve French20962432005-09-21 22:05:57 -07004882/* Query File System Info such as free space to old servers such as Win 9x */
4883int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004884SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4885 struct kstatfs *FSData)
Steve French20962432005-09-21 22:05:57 -07004886{
4887/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4888 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4889 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4890 FILE_SYSTEM_ALLOC_INFO *response_data;
4891 int rc = 0;
4892 int bytes_returned = 0;
4893 __u16 params, byte_count;
4894
Joe Perchesb6b38f72010-04-21 03:50:45 +00004895 cFYI(1, "OldQFSInfo");
Steve French20962432005-09-21 22:05:57 -07004896oldQFSInfoRetry:
4897 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4898 (void **) &pSMBr);
4899 if (rc)
4900 return rc;
Steve French20962432005-09-21 22:05:57 -07004901
4902 params = 2; /* level */
4903 pSMB->TotalDataCount = 0;
4904 pSMB->MaxParameterCount = cpu_to_le16(2);
4905 pSMB->MaxDataCount = cpu_to_le16(1000);
4906 pSMB->MaxSetupCount = 0;
4907 pSMB->Reserved = 0;
4908 pSMB->Flags = 0;
4909 pSMB->Timeout = 0;
4910 pSMB->Reserved2 = 0;
4911 byte_count = params + 1 /* pad */ ;
4912 pSMB->TotalParameterCount = cpu_to_le16(params);
4913 pSMB->ParameterCount = pSMB->TotalParameterCount;
4914 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4915 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4916 pSMB->DataCount = 0;
4917 pSMB->DataOffset = 0;
4918 pSMB->SetupCount = 1;
4919 pSMB->Reserved3 = 0;
4920 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4921 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004922 inc_rfc1001_len(pSMB, byte_count);
Steve French20962432005-09-21 22:05:57 -07004923 pSMB->ByteCount = cpu_to_le16(byte_count);
4924
4925 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4926 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4927 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004928 cFYI(1, "Send error in QFSInfo = %d", rc);
Steve French20962432005-09-21 22:05:57 -07004929 } else { /* decode response */
4930 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4931
Jeff Layton820a8032011-05-04 08:05:26 -04004932 if (rc || get_bcc(&pSMBr->hdr) < 18)
Steve French20962432005-09-21 22:05:57 -07004933 rc = -EIO; /* bad smb */
4934 else {
4935 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004936 cFYI(1, "qfsinf resp BCC: %d Offset %d",
Jeff Layton820a8032011-05-04 08:05:26 -04004937 get_bcc(&pSMBr->hdr), data_offset);
Steve French20962432005-09-21 22:05:57 -07004938
Steve French50c2f752007-07-13 00:33:32 +00004939 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004940 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4941 FSData->f_bsize =
4942 le16_to_cpu(response_data->BytesPerSector) *
4943 le32_to_cpu(response_data->
4944 SectorsPerAllocationUnit);
4945 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004946 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004947 FSData->f_bfree = FSData->f_bavail =
4948 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004949 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
4950 (unsigned long long)FSData->f_blocks,
4951 (unsigned long long)FSData->f_bfree,
4952 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07004953 }
4954 }
4955 cifs_buf_release(pSMB);
4956
4957 if (rc == -EAGAIN)
4958 goto oldQFSInfoRetry;
4959
4960 return rc;
4961}
4962
Linus Torvalds1da177e2005-04-16 15:20:36 -07004963int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004964CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4965 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004966{
4967/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4968 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4969 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4970 FILE_SYSTEM_INFO *response_data;
4971 int rc = 0;
4972 int bytes_returned = 0;
4973 __u16 params, byte_count;
4974
Joe Perchesb6b38f72010-04-21 03:50:45 +00004975 cFYI(1, "In QFSInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004976QFSInfoRetry:
4977 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4978 (void **) &pSMBr);
4979 if (rc)
4980 return rc;
4981
4982 params = 2; /* level */
4983 pSMB->TotalDataCount = 0;
4984 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004985 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004986 pSMB->MaxSetupCount = 0;
4987 pSMB->Reserved = 0;
4988 pSMB->Flags = 0;
4989 pSMB->Timeout = 0;
4990 pSMB->Reserved2 = 0;
4991 byte_count = params + 1 /* pad */ ;
4992 pSMB->TotalParameterCount = cpu_to_le16(params);
4993 pSMB->ParameterCount = pSMB->TotalParameterCount;
4994 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004995 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004996 pSMB->DataCount = 0;
4997 pSMB->DataOffset = 0;
4998 pSMB->SetupCount = 1;
4999 pSMB->Reserved3 = 0;
5000 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5001 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005002 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005003 pSMB->ByteCount = cpu_to_le16(byte_count);
5004
5005 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5006 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5007 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005008 cFYI(1, "Send error in QFSInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005009 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00005010 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005011
Jeff Layton820a8032011-05-04 08:05:26 -04005012 if (rc || get_bcc(&pSMBr->hdr) < 24)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005013 rc = -EIO; /* bad smb */
5014 else {
5015 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005016
5017 response_data =
5018 (FILE_SYSTEM_INFO
5019 *) (((char *) &pSMBr->hdr.Protocol) +
5020 data_offset);
5021 FSData->f_bsize =
5022 le32_to_cpu(response_data->BytesPerSector) *
5023 le32_to_cpu(response_data->
5024 SectorsPerAllocationUnit);
5025 FSData->f_blocks =
5026 le64_to_cpu(response_data->TotalAllocationUnits);
5027 FSData->f_bfree = FSData->f_bavail =
5028 le64_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesb6b38f72010-04-21 03:50:45 +00005029 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
5030 (unsigned long long)FSData->f_blocks,
5031 (unsigned long long)FSData->f_bfree,
5032 FSData->f_bsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005033 }
5034 }
5035 cifs_buf_release(pSMB);
5036
5037 if (rc == -EAGAIN)
5038 goto QFSInfoRetry;
5039
5040 return rc;
5041}
5042
5043int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005044CIFSSMBQFSAttributeInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005045{
5046/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
5047 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5048 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5049 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
5050 int rc = 0;
5051 int bytes_returned = 0;
5052 __u16 params, byte_count;
5053
Joe Perchesb6b38f72010-04-21 03:50:45 +00005054 cFYI(1, "In QFSAttributeInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005055QFSAttributeRetry:
5056 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5057 (void **) &pSMBr);
5058 if (rc)
5059 return rc;
5060
5061 params = 2; /* level */
5062 pSMB->TotalDataCount = 0;
5063 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005064 /* BB find exact max SMB PDU from sess structure BB */
5065 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005066 pSMB->MaxSetupCount = 0;
5067 pSMB->Reserved = 0;
5068 pSMB->Flags = 0;
5069 pSMB->Timeout = 0;
5070 pSMB->Reserved2 = 0;
5071 byte_count = params + 1 /* pad */ ;
5072 pSMB->TotalParameterCount = cpu_to_le16(params);
5073 pSMB->ParameterCount = pSMB->TotalParameterCount;
5074 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005075 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005076 pSMB->DataCount = 0;
5077 pSMB->DataOffset = 0;
5078 pSMB->SetupCount = 1;
5079 pSMB->Reserved3 = 0;
5080 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5081 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005082 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005083 pSMB->ByteCount = cpu_to_le16(byte_count);
5084
5085 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5086 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5087 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005088 cERROR(1, "Send error in QFSAttributeInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005089 } else { /* decode response */
5090 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5091
Jeff Layton820a8032011-05-04 08:05:26 -04005092 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Steve French50c2f752007-07-13 00:33:32 +00005093 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005094 rc = -EIO; /* bad smb */
5095 } else {
5096 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5097 response_data =
5098 (FILE_SYSTEM_ATTRIBUTE_INFO
5099 *) (((char *) &pSMBr->hdr.Protocol) +
5100 data_offset);
5101 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005102 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005103 }
5104 }
5105 cifs_buf_release(pSMB);
5106
5107 if (rc == -EAGAIN)
5108 goto QFSAttributeRetry;
5109
5110 return rc;
5111}
5112
5113int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005114CIFSSMBQFSDeviceInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005115{
5116/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
5117 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5118 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5119 FILE_SYSTEM_DEVICE_INFO *response_data;
5120 int rc = 0;
5121 int bytes_returned = 0;
5122 __u16 params, byte_count;
5123
Joe Perchesb6b38f72010-04-21 03:50:45 +00005124 cFYI(1, "In QFSDeviceInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005125QFSDeviceRetry:
5126 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5127 (void **) &pSMBr);
5128 if (rc)
5129 return rc;
5130
5131 params = 2; /* level */
5132 pSMB->TotalDataCount = 0;
5133 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005134 /* BB find exact max SMB PDU from sess structure BB */
5135 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005136 pSMB->MaxSetupCount = 0;
5137 pSMB->Reserved = 0;
5138 pSMB->Flags = 0;
5139 pSMB->Timeout = 0;
5140 pSMB->Reserved2 = 0;
5141 byte_count = params + 1 /* pad */ ;
5142 pSMB->TotalParameterCount = cpu_to_le16(params);
5143 pSMB->ParameterCount = pSMB->TotalParameterCount;
5144 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005145 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005146
5147 pSMB->DataCount = 0;
5148 pSMB->DataOffset = 0;
5149 pSMB->SetupCount = 1;
5150 pSMB->Reserved3 = 0;
5151 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5152 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005153 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005154 pSMB->ByteCount = cpu_to_le16(byte_count);
5155
5156 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5157 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5158 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005159 cFYI(1, "Send error in QFSDeviceInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005160 } else { /* decode response */
5161 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5162
Jeff Layton820a8032011-05-04 08:05:26 -04005163 if (rc || get_bcc(&pSMBr->hdr) <
5164 sizeof(FILE_SYSTEM_DEVICE_INFO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005165 rc = -EIO; /* bad smb */
5166 else {
5167 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5168 response_data =
Steve French737b7582005-04-28 22:41:06 -07005169 (FILE_SYSTEM_DEVICE_INFO *)
5170 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07005171 data_offset);
5172 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005173 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005174 }
5175 }
5176 cifs_buf_release(pSMB);
5177
5178 if (rc == -EAGAIN)
5179 goto QFSDeviceRetry;
5180
5181 return rc;
5182}
5183
5184int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005185CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005186{
5187/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
5188 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5189 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5190 FILE_SYSTEM_UNIX_INFO *response_data;
5191 int rc = 0;
5192 int bytes_returned = 0;
5193 __u16 params, byte_count;
5194
Joe Perchesb6b38f72010-04-21 03:50:45 +00005195 cFYI(1, "In QFSUnixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005196QFSUnixRetry:
Jeff Laytonf5695992010-09-29 15:27:08 -04005197 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5198 (void **) &pSMB, (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005199 if (rc)
5200 return rc;
5201
5202 params = 2; /* level */
5203 pSMB->TotalDataCount = 0;
5204 pSMB->DataCount = 0;
5205 pSMB->DataOffset = 0;
5206 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005207 /* BB find exact max SMB PDU from sess structure BB */
5208 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005209 pSMB->MaxSetupCount = 0;
5210 pSMB->Reserved = 0;
5211 pSMB->Flags = 0;
5212 pSMB->Timeout = 0;
5213 pSMB->Reserved2 = 0;
5214 byte_count = params + 1 /* pad */ ;
5215 pSMB->ParameterCount = cpu_to_le16(params);
5216 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005217 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5218 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005219 pSMB->SetupCount = 1;
5220 pSMB->Reserved3 = 0;
5221 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5222 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005223 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005224 pSMB->ByteCount = cpu_to_le16(byte_count);
5225
5226 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5227 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5228 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005229 cERROR(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005230 } else { /* decode response */
5231 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5232
Jeff Layton820a8032011-05-04 08:05:26 -04005233 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005234 rc = -EIO; /* bad smb */
5235 } else {
5236 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5237 response_data =
5238 (FILE_SYSTEM_UNIX_INFO
5239 *) (((char *) &pSMBr->hdr.Protocol) +
5240 data_offset);
5241 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005242 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005243 }
5244 }
5245 cifs_buf_release(pSMB);
5246
5247 if (rc == -EAGAIN)
5248 goto QFSUnixRetry;
5249
5250
5251 return rc;
5252}
5253
Jeremy Allisonac670552005-06-22 17:26:35 -07005254int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005255CIFSSMBSetFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07005256{
5257/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
5258 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
5259 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
5260 int rc = 0;
5261 int bytes_returned = 0;
5262 __u16 params, param_offset, offset, byte_count;
5263
Joe Perchesb6b38f72010-04-21 03:50:45 +00005264 cFYI(1, "In SETFSUnixInfo");
Jeremy Allisonac670552005-06-22 17:26:35 -07005265SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00005266 /* BB switch to small buf init to save memory */
Jeff Laytonf5695992010-09-29 15:27:08 -04005267 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5268 (void **) &pSMB, (void **) &pSMBr);
Jeremy Allisonac670552005-06-22 17:26:35 -07005269 if (rc)
5270 return rc;
5271
5272 params = 4; /* 2 bytes zero followed by info level. */
5273 pSMB->MaxSetupCount = 0;
5274 pSMB->Reserved = 0;
5275 pSMB->Flags = 0;
5276 pSMB->Timeout = 0;
5277 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00005278 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
5279 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07005280 offset = param_offset + params;
5281
5282 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00005283 /* BB find exact max SMB PDU from sess structure BB */
5284 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07005285 pSMB->SetupCount = 1;
5286 pSMB->Reserved3 = 0;
5287 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
5288 byte_count = 1 /* pad */ + params + 12;
5289
5290 pSMB->DataCount = cpu_to_le16(12);
5291 pSMB->ParameterCount = cpu_to_le16(params);
5292 pSMB->TotalDataCount = pSMB->DataCount;
5293 pSMB->TotalParameterCount = pSMB->ParameterCount;
5294 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5295 pSMB->DataOffset = cpu_to_le16(offset);
5296
5297 /* Params. */
5298 pSMB->FileNum = 0;
5299 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
5300
5301 /* Data. */
5302 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
5303 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
5304 pSMB->ClientUnixCap = cpu_to_le64(cap);
5305
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005306 inc_rfc1001_len(pSMB, byte_count);
Jeremy Allisonac670552005-06-22 17:26:35 -07005307 pSMB->ByteCount = cpu_to_le16(byte_count);
5308
5309 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5310 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5311 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005312 cERROR(1, "Send error in SETFSUnixInfo = %d", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07005313 } else { /* decode response */
5314 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00005315 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07005316 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07005317 }
5318 cifs_buf_release(pSMB);
5319
5320 if (rc == -EAGAIN)
5321 goto SETFSUnixRetry;
5322
5323 return rc;
5324}
5325
5326
Linus Torvalds1da177e2005-04-16 15:20:36 -07005327
5328int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005329CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon,
Steve French737b7582005-04-28 22:41:06 -07005330 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005331{
5332/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
5333 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5334 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5335 FILE_SYSTEM_POSIX_INFO *response_data;
5336 int rc = 0;
5337 int bytes_returned = 0;
5338 __u16 params, byte_count;
5339
Joe Perchesb6b38f72010-04-21 03:50:45 +00005340 cFYI(1, "In QFSPosixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005341QFSPosixRetry:
5342 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5343 (void **) &pSMBr);
5344 if (rc)
5345 return rc;
5346
5347 params = 2; /* level */
5348 pSMB->TotalDataCount = 0;
5349 pSMB->DataCount = 0;
5350 pSMB->DataOffset = 0;
5351 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005352 /* BB find exact max SMB PDU from sess structure BB */
5353 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005354 pSMB->MaxSetupCount = 0;
5355 pSMB->Reserved = 0;
5356 pSMB->Flags = 0;
5357 pSMB->Timeout = 0;
5358 pSMB->Reserved2 = 0;
5359 byte_count = params + 1 /* pad */ ;
5360 pSMB->ParameterCount = cpu_to_le16(params);
5361 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005362 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5363 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005364 pSMB->SetupCount = 1;
5365 pSMB->Reserved3 = 0;
5366 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5367 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005368 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005369 pSMB->ByteCount = cpu_to_le16(byte_count);
5370
5371 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5372 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5373 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005374 cFYI(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005375 } else { /* decode response */
5376 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5377
Jeff Layton820a8032011-05-04 08:05:26 -04005378 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005379 rc = -EIO; /* bad smb */
5380 } else {
5381 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5382 response_data =
5383 (FILE_SYSTEM_POSIX_INFO
5384 *) (((char *) &pSMBr->hdr.Protocol) +
5385 data_offset);
5386 FSData->f_bsize =
5387 le32_to_cpu(response_data->BlockSize);
5388 FSData->f_blocks =
5389 le64_to_cpu(response_data->TotalBlocks);
5390 FSData->f_bfree =
5391 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00005392 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005393 FSData->f_bavail = FSData->f_bfree;
5394 } else {
5395 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00005396 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005397 }
Steve French790fe572007-07-07 19:25:05 +00005398 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005399 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00005400 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00005401 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005402 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00005403 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005404 }
5405 }
5406 cifs_buf_release(pSMB);
5407
5408 if (rc == -EAGAIN)
5409 goto QFSPosixRetry;
5410
5411 return rc;
5412}
5413
5414
Steve French50c2f752007-07-13 00:33:32 +00005415/* We can not use write of zero bytes trick to
5416 set file size due to need for large file support. Also note that
5417 this SetPathInfo is preferred to SetFileInfo based method in next
Linus Torvalds1da177e2005-04-16 15:20:36 -07005418 routine which is only needed to work around a sharing violation bug
5419 in Samba which this routine can run into */
5420
5421int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005422CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
5423 const char *fileName, __u64 size, bool SetAllocation,
Steve French737b7582005-04-28 22:41:06 -07005424 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005425{
5426 struct smb_com_transaction2_spi_req *pSMB = NULL;
5427 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5428 struct file_end_of_file_info *parm_data;
5429 int name_len;
5430 int rc = 0;
5431 int bytes_returned = 0;
5432 __u16 params, byte_count, data_count, param_offset, offset;
5433
Joe Perchesb6b38f72010-04-21 03:50:45 +00005434 cFYI(1, "In SetEOF");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005435SetEOFRetry:
5436 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5437 (void **) &pSMBr);
5438 if (rc)
5439 return rc;
5440
5441 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5442 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005443 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5444 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005445 name_len++; /* trailing null */
5446 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005447 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005448 name_len = strnlen(fileName, PATH_MAX);
5449 name_len++; /* trailing null */
5450 strncpy(pSMB->FileName, fileName, name_len);
5451 }
5452 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005453 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005454 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07005455 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005456 pSMB->MaxSetupCount = 0;
5457 pSMB->Reserved = 0;
5458 pSMB->Flags = 0;
5459 pSMB->Timeout = 0;
5460 pSMB->Reserved2 = 0;
5461 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005462 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005463 offset = param_offset + params;
Steve French790fe572007-07-07 19:25:05 +00005464 if (SetAllocation) {
Steve French50c2f752007-07-13 00:33:32 +00005465 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5466 pSMB->InformationLevel =
5467 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5468 else
5469 pSMB->InformationLevel =
5470 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5471 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005472 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5473 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005474 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005475 else
5476 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005477 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005478 }
5479
5480 parm_data =
5481 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
5482 offset);
5483 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5484 pSMB->DataOffset = cpu_to_le16(offset);
5485 pSMB->SetupCount = 1;
5486 pSMB->Reserved3 = 0;
5487 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5488 byte_count = 3 /* pad */ + params + data_count;
5489 pSMB->DataCount = cpu_to_le16(data_count);
5490 pSMB->TotalDataCount = pSMB->DataCount;
5491 pSMB->ParameterCount = cpu_to_le16(params);
5492 pSMB->TotalParameterCount = pSMB->ParameterCount;
5493 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005494 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005495 parm_data->FileSize = cpu_to_le64(size);
5496 pSMB->ByteCount = cpu_to_le16(byte_count);
5497 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5498 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005499 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005500 cFYI(1, "SetPathInfo (file size) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005501
5502 cifs_buf_release(pSMB);
5503
5504 if (rc == -EAGAIN)
5505 goto SetEOFRetry;
5506
5507 return rc;
5508}
5509
5510int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005511CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon, __u64 size,
Steve French4b18f2a2008-04-29 00:06:05 +00005512 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005513{
5514 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005515 struct file_end_of_file_info *parm_data;
5516 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005517 __u16 params, param_offset, offset, byte_count, count;
5518
Joe Perchesb6b38f72010-04-21 03:50:45 +00005519 cFYI(1, "SetFileSize (via SetFileInfo) %lld",
5520 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07005521 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5522
Linus Torvalds1da177e2005-04-16 15:20:36 -07005523 if (rc)
5524 return rc;
5525
5526 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5527 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005528
Linus Torvalds1da177e2005-04-16 15:20:36 -07005529 params = 6;
5530 pSMB->MaxSetupCount = 0;
5531 pSMB->Reserved = 0;
5532 pSMB->Flags = 0;
5533 pSMB->Timeout = 0;
5534 pSMB->Reserved2 = 0;
5535 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5536 offset = param_offset + params;
5537
Linus Torvalds1da177e2005-04-16 15:20:36 -07005538 count = sizeof(struct file_end_of_file_info);
5539 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005540 /* BB find exact max SMB PDU from sess structure BB */
5541 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005542 pSMB->SetupCount = 1;
5543 pSMB->Reserved3 = 0;
5544 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5545 byte_count = 3 /* pad */ + params + count;
5546 pSMB->DataCount = cpu_to_le16(count);
5547 pSMB->ParameterCount = cpu_to_le16(params);
5548 pSMB->TotalDataCount = pSMB->DataCount;
5549 pSMB->TotalParameterCount = pSMB->ParameterCount;
5550 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5551 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00005552 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
5553 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005554 pSMB->DataOffset = cpu_to_le16(offset);
5555 parm_data->FileSize = cpu_to_le64(size);
5556 pSMB->Fid = fid;
Steve French790fe572007-07-07 19:25:05 +00005557 if (SetAllocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005558 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5559 pSMB->InformationLevel =
5560 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5561 else
5562 pSMB->InformationLevel =
5563 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00005564 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005565 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5566 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005567 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005568 else
5569 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005570 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005571 }
5572 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005573 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005574 pSMB->ByteCount = cpu_to_le16(byte_count);
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005575 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005576 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005577 cFYI(1, "Send error in SetFileInfo (SetFileSize) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005578 }
5579
Steve French50c2f752007-07-13 00:33:32 +00005580 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005581 since file handle passed in no longer valid */
5582
5583 return rc;
5584}
5585
Steve French50c2f752007-07-13 00:33:32 +00005586/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07005587 an open handle, rather than by pathname - this is awkward due to
5588 potential access conflicts on the open, but it is unavoidable for these
5589 old servers since the only other choice is to go from 100 nanosecond DCE
5590 time and resort to the original setpathinfo level which takes the ancient
5591 DOS time format with 2 second granularity */
5592int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005593CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005594 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005595{
5596 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005597 char *data_offset;
5598 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005599 __u16 params, param_offset, offset, byte_count, count;
5600
Joe Perchesb6b38f72010-04-21 03:50:45 +00005601 cFYI(1, "Set Times (via SetFileInfo)");
Steve Frenchcd634992005-04-28 22:41:10 -07005602 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5603
Linus Torvalds1da177e2005-04-16 15:20:36 -07005604 if (rc)
5605 return rc;
5606
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005607 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5608 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005609
Linus Torvalds1da177e2005-04-16 15:20:36 -07005610 params = 6;
5611 pSMB->MaxSetupCount = 0;
5612 pSMB->Reserved = 0;
5613 pSMB->Flags = 0;
5614 pSMB->Timeout = 0;
5615 pSMB->Reserved2 = 0;
5616 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5617 offset = param_offset + params;
5618
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005619 data_offset = (char *)pSMB +
5620 offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005621
Steve French26f57362007-08-30 22:09:15 +00005622 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005623 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005624 /* BB find max SMB PDU from sess */
5625 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005626 pSMB->SetupCount = 1;
5627 pSMB->Reserved3 = 0;
5628 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5629 byte_count = 3 /* pad */ + params + count;
5630 pSMB->DataCount = cpu_to_le16(count);
5631 pSMB->ParameterCount = cpu_to_le16(params);
5632 pSMB->TotalDataCount = pSMB->DataCount;
5633 pSMB->TotalParameterCount = pSMB->ParameterCount;
5634 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5635 pSMB->DataOffset = cpu_to_le16(offset);
5636 pSMB->Fid = fid;
5637 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5638 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5639 else
5640 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5641 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005642 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005643 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005644 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005645 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005646 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005647 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005648
Steve French50c2f752007-07-13 00:33:32 +00005649 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005650 since file handle passed in no longer valid */
5651
5652 return rc;
5653}
5654
Jeff Layton6d22f092008-09-23 11:48:35 -04005655int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005656CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6d22f092008-09-23 11:48:35 -04005657 bool delete_file, __u16 fid, __u32 pid_of_opener)
5658{
5659 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5660 char *data_offset;
5661 int rc = 0;
5662 __u16 params, param_offset, offset, byte_count, count;
5663
Joe Perchesb6b38f72010-04-21 03:50:45 +00005664 cFYI(1, "Set File Disposition (via SetFileInfo)");
Jeff Layton6d22f092008-09-23 11:48:35 -04005665 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5666
5667 if (rc)
5668 return rc;
5669
5670 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5671 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5672
5673 params = 6;
5674 pSMB->MaxSetupCount = 0;
5675 pSMB->Reserved = 0;
5676 pSMB->Flags = 0;
5677 pSMB->Timeout = 0;
5678 pSMB->Reserved2 = 0;
5679 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5680 offset = param_offset + params;
5681
5682 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5683
5684 count = 1;
5685 pSMB->MaxParameterCount = cpu_to_le16(2);
5686 /* BB find max SMB PDU from sess */
5687 pSMB->MaxDataCount = cpu_to_le16(1000);
5688 pSMB->SetupCount = 1;
5689 pSMB->Reserved3 = 0;
5690 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5691 byte_count = 3 /* pad */ + params + count;
5692 pSMB->DataCount = cpu_to_le16(count);
5693 pSMB->ParameterCount = cpu_to_le16(params);
5694 pSMB->TotalDataCount = pSMB->DataCount;
5695 pSMB->TotalParameterCount = pSMB->ParameterCount;
5696 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5697 pSMB->DataOffset = cpu_to_le16(offset);
5698 pSMB->Fid = fid;
5699 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5700 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005701 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton6d22f092008-09-23 11:48:35 -04005702 pSMB->ByteCount = cpu_to_le16(byte_count);
5703 *data_offset = delete_file ? 1 : 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005704 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Jeff Layton6d22f092008-09-23 11:48:35 -04005705 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005706 cFYI(1, "Send error in SetFileDisposition = %d", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005707
5708 return rc;
5709}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005710
5711int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005712CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6fc000e2008-08-02 07:26:12 -04005713 const char *fileName, const FILE_BASIC_INFO *data,
5714 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005715{
5716 TRANSACTION2_SPI_REQ *pSMB = NULL;
5717 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5718 int name_len;
5719 int rc = 0;
5720 int bytes_returned = 0;
5721 char *data_offset;
5722 __u16 params, param_offset, offset, byte_count, count;
5723
Joe Perchesb6b38f72010-04-21 03:50:45 +00005724 cFYI(1, "In SetTimes");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005725
5726SetTimesRetry:
5727 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5728 (void **) &pSMBr);
5729 if (rc)
5730 return rc;
5731
5732 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5733 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005734 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5735 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005736 name_len++; /* trailing null */
5737 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005738 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005739 name_len = strnlen(fileName, PATH_MAX);
5740 name_len++; /* trailing null */
5741 strncpy(pSMB->FileName, fileName, name_len);
5742 }
5743
5744 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005745 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005746 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005747 /* BB find max SMB PDU from sess structure BB */
5748 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005749 pSMB->MaxSetupCount = 0;
5750 pSMB->Reserved = 0;
5751 pSMB->Flags = 0;
5752 pSMB->Timeout = 0;
5753 pSMB->Reserved2 = 0;
5754 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005755 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005756 offset = param_offset + params;
5757 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5758 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5759 pSMB->DataOffset = cpu_to_le16(offset);
5760 pSMB->SetupCount = 1;
5761 pSMB->Reserved3 = 0;
5762 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5763 byte_count = 3 /* pad */ + params + count;
5764
5765 pSMB->DataCount = cpu_to_le16(count);
5766 pSMB->ParameterCount = cpu_to_le16(params);
5767 pSMB->TotalDataCount = pSMB->DataCount;
5768 pSMB->TotalParameterCount = pSMB->ParameterCount;
5769 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5770 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5771 else
5772 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5773 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005774 inc_rfc1001_len(pSMB, byte_count);
Steve French26f57362007-08-30 22:09:15 +00005775 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005776 pSMB->ByteCount = cpu_to_le16(byte_count);
5777 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5778 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005779 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005780 cFYI(1, "SetPathInfo (times) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005781
5782 cifs_buf_release(pSMB);
5783
5784 if (rc == -EAGAIN)
5785 goto SetTimesRetry;
5786
5787 return rc;
5788}
5789
5790/* Can not be used to set time stamps yet (due to old DOS time format) */
5791/* Can be used to set attributes */
5792#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5793 handling it anyway and NT4 was what we thought it would be needed for
5794 Do not delete it until we prove whether needed for Win9x though */
5795int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005796CIFSSMBSetAttrLegacy(unsigned int xid, struct cifs_tcon *tcon, char *fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005797 __u16 dos_attrs, const struct nls_table *nls_codepage)
5798{
5799 SETATTR_REQ *pSMB = NULL;
5800 SETATTR_RSP *pSMBr = NULL;
5801 int rc = 0;
5802 int bytes_returned;
5803 int name_len;
5804
Joe Perchesb6b38f72010-04-21 03:50:45 +00005805 cFYI(1, "In SetAttrLegacy");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005806
5807SetAttrLgcyRetry:
5808 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5809 (void **) &pSMBr);
5810 if (rc)
5811 return rc;
5812
5813 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5814 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005815 ConvertToUTF16((__le16 *) pSMB->fileName, fileName,
5816 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005817 name_len++; /* trailing null */
5818 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005819 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005820 name_len = strnlen(fileName, PATH_MAX);
5821 name_len++; /* trailing null */
5822 strncpy(pSMB->fileName, fileName, name_len);
5823 }
5824 pSMB->attr = cpu_to_le16(dos_attrs);
5825 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005826 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005827 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5828 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5829 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005830 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005831 cFYI(1, "Error in LegacySetAttr = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005832
5833 cifs_buf_release(pSMB);
5834
5835 if (rc == -EAGAIN)
5836 goto SetAttrLgcyRetry;
5837
5838 return rc;
5839}
5840#endif /* temporarily unneeded SetAttr legacy function */
5841
Jeff Layton654cf142009-07-09 20:02:49 -04005842static void
5843cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5844 const struct cifs_unix_set_info_args *args)
5845{
5846 u64 mode = args->mode;
5847
5848 /*
5849 * Samba server ignores set of file size to zero due to bugs in some
5850 * older clients, but we should be precise - we use SetFileSize to
5851 * set file size and do not want to truncate file size to zero
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005852 * accidentally as happened on one Samba server beta by putting
Jeff Layton654cf142009-07-09 20:02:49 -04005853 * zero instead of -1 here
5854 */
5855 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5856 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5857 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5858 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5859 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5860 data_offset->Uid = cpu_to_le64(args->uid);
5861 data_offset->Gid = cpu_to_le64(args->gid);
5862 /* better to leave device as zero when it is */
5863 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5864 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5865 data_offset->Permissions = cpu_to_le64(mode);
5866
5867 if (S_ISREG(mode))
5868 data_offset->Type = cpu_to_le32(UNIX_FILE);
5869 else if (S_ISDIR(mode))
5870 data_offset->Type = cpu_to_le32(UNIX_DIR);
5871 else if (S_ISLNK(mode))
5872 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5873 else if (S_ISCHR(mode))
5874 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5875 else if (S_ISBLK(mode))
5876 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5877 else if (S_ISFIFO(mode))
5878 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5879 else if (S_ISSOCK(mode))
5880 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5881}
5882
Linus Torvalds1da177e2005-04-16 15:20:36 -07005883int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005884CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005885 const struct cifs_unix_set_info_args *args,
5886 u16 fid, u32 pid_of_opener)
5887{
5888 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005889 char *data_offset;
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005890 int rc = 0;
5891 u16 params, param_offset, offset, byte_count, count;
5892
Joe Perchesb6b38f72010-04-21 03:50:45 +00005893 cFYI(1, "Set Unix Info (via SetFileInfo)");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005894 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5895
5896 if (rc)
5897 return rc;
5898
5899 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5900 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5901
5902 params = 6;
5903 pSMB->MaxSetupCount = 0;
5904 pSMB->Reserved = 0;
5905 pSMB->Flags = 0;
5906 pSMB->Timeout = 0;
5907 pSMB->Reserved2 = 0;
5908 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5909 offset = param_offset + params;
5910
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005911 data_offset = (char *)pSMB +
5912 offsetof(struct smb_hdr, Protocol) + offset;
5913
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005914 count = sizeof(FILE_UNIX_BASIC_INFO);
5915
5916 pSMB->MaxParameterCount = cpu_to_le16(2);
5917 /* BB find max SMB PDU from sess */
5918 pSMB->MaxDataCount = cpu_to_le16(1000);
5919 pSMB->SetupCount = 1;
5920 pSMB->Reserved3 = 0;
5921 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5922 byte_count = 3 /* pad */ + params + count;
5923 pSMB->DataCount = cpu_to_le16(count);
5924 pSMB->ParameterCount = cpu_to_le16(params);
5925 pSMB->TotalDataCount = pSMB->DataCount;
5926 pSMB->TotalParameterCount = pSMB->ParameterCount;
5927 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5928 pSMB->DataOffset = cpu_to_le16(offset);
5929 pSMB->Fid = fid;
5930 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5931 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005932 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005933 pSMB->ByteCount = cpu_to_le16(byte_count);
5934
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005935 cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005936
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005937 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005938 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005939 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005940
5941 /* Note: On -EAGAIN error only caller can retry on handle based calls
5942 since file handle passed in no longer valid */
5943
5944 return rc;
5945}
5946
5947int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005948CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005949 const char *file_name,
Jeff Layton01ea95e2009-07-09 20:02:49 -04005950 const struct cifs_unix_set_info_args *args,
5951 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005952{
5953 TRANSACTION2_SPI_REQ *pSMB = NULL;
5954 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5955 int name_len;
5956 int rc = 0;
5957 int bytes_returned = 0;
5958 FILE_UNIX_BASIC_INFO *data_offset;
5959 __u16 params, param_offset, offset, count, byte_count;
5960
Joe Perchesb6b38f72010-04-21 03:50:45 +00005961 cFYI(1, "In SetUID/GID/Mode");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005962setPermsRetry:
5963 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5964 (void **) &pSMBr);
5965 if (rc)
5966 return rc;
5967
5968 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5969 name_len =
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005970 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06005971 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005972 name_len++; /* trailing null */
5973 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005974 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005975 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005976 name_len++; /* trailing null */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005977 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005978 }
5979
5980 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005981 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005982 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005983 /* BB find max SMB PDU from sess structure BB */
5984 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005985 pSMB->MaxSetupCount = 0;
5986 pSMB->Reserved = 0;
5987 pSMB->Flags = 0;
5988 pSMB->Timeout = 0;
5989 pSMB->Reserved2 = 0;
5990 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005991 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005992 offset = param_offset + params;
5993 data_offset =
5994 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5995 offset);
5996 memset(data_offset, 0, count);
5997 pSMB->DataOffset = cpu_to_le16(offset);
5998 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5999 pSMB->SetupCount = 1;
6000 pSMB->Reserved3 = 0;
6001 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6002 byte_count = 3 /* pad */ + params + count;
6003 pSMB->ParameterCount = cpu_to_le16(params);
6004 pSMB->DataCount = cpu_to_le16(count);
6005 pSMB->TotalParameterCount = pSMB->ParameterCount;
6006 pSMB->TotalDataCount = pSMB->DataCount;
6007 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6008 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006009 inc_rfc1001_len(pSMB, byte_count);
Steve French50c2f752007-07-13 00:33:32 +00006010
Jeff Layton654cf142009-07-09 20:02:49 -04006011 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006012
6013 pSMB->ByteCount = cpu_to_le16(byte_count);
6014 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6015 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006016 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00006017 cFYI(1, "SetPathInfo (perms) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006018
Steve French0d817bc2008-05-22 02:02:03 +00006019 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006020 if (rc == -EAGAIN)
6021 goto setPermsRetry;
6022 return rc;
6023}
6024
Linus Torvalds1da177e2005-04-16 15:20:36 -07006025#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05006026/*
6027 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
6028 * function used by listxattr and getxattr type calls. When ea_name is set,
6029 * it looks for that attribute name and stuffs that value into the EAData
6030 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
6031 * buffer. In both cases, the return value is either the length of the
6032 * resulting data or a negative error code. If EAData is a NULL pointer then
6033 * the data isn't copied to it, but the length is returned.
6034 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006035ssize_t
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006036CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05006037 const unsigned char *searchName, const unsigned char *ea_name,
6038 char *EAData, size_t buf_size,
6039 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006040{
6041 /* BB assumes one setup word */
6042 TRANSACTION2_QPI_REQ *pSMB = NULL;
6043 TRANSACTION2_QPI_RSP *pSMBr = NULL;
6044 int rc = 0;
6045 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05006046 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006047 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00006048 struct fea *temp_fea;
6049 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006050 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006051 __u16 params, byte_count, data_offset;
Jeff Layton5980fc92011-07-28 12:48:26 -04006052 unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006053
Joe Perchesb6b38f72010-04-21 03:50:45 +00006054 cFYI(1, "In Query All EAs path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006055QAllEAsRetry:
6056 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6057 (void **) &pSMBr);
6058 if (rc)
6059 return rc;
6060
6061 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05006062 list_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006063 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
6064 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05006065 list_len++; /* trailing null */
6066 list_len *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006067 } else { /* BB improve the check for buffer overruns BB */
Jeff Layton6e462b92010-02-10 16:18:26 -05006068 list_len = strnlen(searchName, PATH_MAX);
6069 list_len++; /* trailing null */
6070 strncpy(pSMB->FileName, searchName, list_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006071 }
6072
Jeff Layton6e462b92010-02-10 16:18:26 -05006073 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006074 pSMB->TotalDataCount = 0;
6075 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006076 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05006077 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006078 pSMB->MaxSetupCount = 0;
6079 pSMB->Reserved = 0;
6080 pSMB->Flags = 0;
6081 pSMB->Timeout = 0;
6082 pSMB->Reserved2 = 0;
6083 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00006084 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006085 pSMB->DataCount = 0;
6086 pSMB->DataOffset = 0;
6087 pSMB->SetupCount = 1;
6088 pSMB->Reserved3 = 0;
6089 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
6090 byte_count = params + 1 /* pad */ ;
6091 pSMB->TotalParameterCount = cpu_to_le16(params);
6092 pSMB->ParameterCount = pSMB->TotalParameterCount;
6093 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
6094 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006095 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006096 pSMB->ByteCount = cpu_to_le16(byte_count);
6097
6098 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6099 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6100 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006101 cFYI(1, "Send error in QueryAllEAs = %d", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05006102 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006103 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006104
6105
6106 /* BB also check enough total bytes returned */
6107 /* BB we need to improve the validity checking
6108 of these trans2 responses */
6109
6110 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Jeff Layton820a8032011-05-04 08:05:26 -04006111 if (rc || get_bcc(&pSMBr->hdr) < 4) {
Jeff Laytonf0d38682010-02-10 16:18:26 -05006112 rc = -EIO; /* bad smb */
6113 goto QAllEAsOut;
6114 }
6115
6116 /* check that length of list is not more than bcc */
6117 /* check that each entry does not go beyond length
6118 of list */
6119 /* check that each element of each entry does not
6120 go beyond end of list */
6121 /* validate_trans2_offsets() */
6122 /* BB check if start of smb + data_offset > &bcc+ bcc */
6123
6124 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
6125 ea_response_data = (struct fealist *)
6126 (((char *) &pSMBr->hdr.Protocol) + data_offset);
6127
Jeff Layton6e462b92010-02-10 16:18:26 -05006128 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesb6b38f72010-04-21 03:50:45 +00006129 cFYI(1, "ea length %d", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05006130 if (list_len <= 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006131 cFYI(1, "empty EA list returned from server");
Jeff Laytonf0d38682010-02-10 16:18:26 -05006132 goto QAllEAsOut;
6133 }
6134
Jeff Layton0cd126b2010-02-10 16:18:26 -05006135 /* make sure list_len doesn't go past end of SMB */
Jeff Layton690c5222011-01-20 13:36:51 -05006136 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
Jeff Layton0cd126b2010-02-10 16:18:26 -05006137 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006138 cFYI(1, "EA list appears to go beyond SMB");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006139 rc = -EIO;
6140 goto QAllEAsOut;
6141 }
6142
Jeff Laytonf0d38682010-02-10 16:18:26 -05006143 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05006144 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006145 temp_fea = ea_response_data->list;
6146 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05006147 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00006148 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006149 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006150
Jeff Layton6e462b92010-02-10 16:18:26 -05006151 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006152 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006153 /* make sure we can read name_len and value_len */
6154 if (list_len < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006155 cFYI(1, "EA entry goes beyond length of list");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006156 rc = -EIO;
6157 goto QAllEAsOut;
6158 }
6159
6160 name_len = temp_fea->name_len;
6161 value_len = le16_to_cpu(temp_fea->value_len);
6162 list_len -= name_len + 1 + value_len;
6163 if (list_len < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006164 cFYI(1, "EA entry goes beyond length of list");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006165 rc = -EIO;
6166 goto QAllEAsOut;
6167 }
6168
Jeff Layton31c05192010-02-10 16:18:26 -05006169 if (ea_name) {
Jeff Layton91d065c2011-07-26 18:23:47 -04006170 if (ea_name_len == name_len &&
Jeff Laytonac423442011-10-11 06:41:32 -04006171 memcmp(ea_name, temp_ptr, name_len) == 0) {
Jeff Layton31c05192010-02-10 16:18:26 -05006172 temp_ptr += name_len + 1;
6173 rc = value_len;
6174 if (buf_size == 0)
6175 goto QAllEAsOut;
6176 if ((size_t)value_len > buf_size) {
6177 rc = -ERANGE;
6178 goto QAllEAsOut;
6179 }
6180 memcpy(EAData, temp_ptr, value_len);
6181 goto QAllEAsOut;
6182 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006183 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05006184 /* account for prefix user. and trailing null */
6185 rc += (5 + 1 + name_len);
6186 if (rc < (int) buf_size) {
6187 memcpy(EAData, "user.", 5);
6188 EAData += 5;
6189 memcpy(EAData, temp_ptr, name_len);
6190 EAData += name_len;
6191 /* null terminate name */
6192 *EAData = 0;
6193 ++EAData;
6194 } else if (buf_size == 0) {
6195 /* skip copy - calc size only */
6196 } else {
6197 /* stop before overrun buffer */
6198 rc = -ERANGE;
6199 break;
6200 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006201 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05006202 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006203 temp_fea = (struct fea *)temp_ptr;
6204 }
6205
Jeff Layton31c05192010-02-10 16:18:26 -05006206 /* didn't find the named attribute */
6207 if (ea_name)
6208 rc = -ENODATA;
6209
Jeff Laytonf0d38682010-02-10 16:18:26 -05006210QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00006211 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006212 if (rc == -EAGAIN)
6213 goto QAllEAsRetry;
6214
6215 return (ssize_t)rc;
6216}
6217
Linus Torvalds1da177e2005-04-16 15:20:36 -07006218int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006219CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
6220 const char *fileName, const char *ea_name, const void *ea_value,
Steve French50c2f752007-07-13 00:33:32 +00006221 const __u16 ea_value_len, const struct nls_table *nls_codepage,
6222 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006223{
6224 struct smb_com_transaction2_spi_req *pSMB = NULL;
6225 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
6226 struct fealist *parm_data;
6227 int name_len;
6228 int rc = 0;
6229 int bytes_returned = 0;
6230 __u16 params, param_offset, byte_count, offset, count;
6231
Joe Perchesb6b38f72010-04-21 03:50:45 +00006232 cFYI(1, "In SetEA");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006233SetEARetry:
6234 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6235 (void **) &pSMBr);
6236 if (rc)
6237 return rc;
6238
6239 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6240 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006241 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
6242 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006243 name_len++; /* trailing null */
6244 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00006245 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006246 name_len = strnlen(fileName, PATH_MAX);
6247 name_len++; /* trailing null */
6248 strncpy(pSMB->FileName, fileName, name_len);
6249 }
6250
6251 params = 6 + name_len;
6252
6253 /* done calculating parms using name_len of file name,
6254 now use name_len to calculate length of ea name
6255 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00006256 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006257 name_len = 0;
6258 else
Steve French50c2f752007-07-13 00:33:32 +00006259 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006260
Steve Frenchdae5dbdb2007-12-30 23:49:57 +00006261 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006262 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006263 /* BB find max SMB PDU from sess */
6264 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006265 pSMB->MaxSetupCount = 0;
6266 pSMB->Reserved = 0;
6267 pSMB->Flags = 0;
6268 pSMB->Timeout = 0;
6269 pSMB->Reserved2 = 0;
6270 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006271 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006272 offset = param_offset + params;
6273 pSMB->InformationLevel =
6274 cpu_to_le16(SMB_SET_FILE_EA);
6275
6276 parm_data =
6277 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
6278 offset);
6279 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6280 pSMB->DataOffset = cpu_to_le16(offset);
6281 pSMB->SetupCount = 1;
6282 pSMB->Reserved3 = 0;
6283 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6284 byte_count = 3 /* pad */ + params + count;
6285 pSMB->DataCount = cpu_to_le16(count);
6286 parm_data->list_len = cpu_to_le32(count);
6287 parm_data->list[0].EA_flags = 0;
6288 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08006289 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006290 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00006291 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00006292 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006293 parm_data->list[0].name[name_len] = 0;
6294 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
6295 /* caller ensures that ea_value_len is less than 64K but
6296 we need to ensure that it fits within the smb */
6297
Steve French50c2f752007-07-13 00:33:32 +00006298 /*BB add length check to see if it would fit in
6299 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00006300 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
6301 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00006302 memcpy(parm_data->list[0].name+name_len+1,
6303 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006304
6305 pSMB->TotalDataCount = pSMB->DataCount;
6306 pSMB->ParameterCount = cpu_to_le16(params);
6307 pSMB->TotalParameterCount = pSMB->ParameterCount;
6308 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006309 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006310 pSMB->ByteCount = cpu_to_le16(byte_count);
6311 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6312 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006313 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00006314 cFYI(1, "SetPathInfo (EA) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006315
6316 cifs_buf_release(pSMB);
6317
6318 if (rc == -EAGAIN)
6319 goto SetEARetry;
6320
6321 return rc;
6322}
Linus Torvalds1da177e2005-04-16 15:20:36 -07006323#endif
Steve French0eff0e22011-02-24 05:39:23 +00006324
6325#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */
6326/*
6327 * Years ago the kernel added a "dnotify" function for Samba server,
6328 * to allow network clients (such as Windows) to display updated
6329 * lists of files in directory listings automatically when
6330 * files are added by one user when another user has the
6331 * same directory open on their desktop. The Linux cifs kernel
6332 * client hooked into the kernel side of this interface for
6333 * the same reason, but ironically when the VFS moved from
6334 * "dnotify" to "inotify" it became harder to plug in Linux
6335 * network file system clients (the most obvious use case
6336 * for notify interfaces is when multiple users can update
6337 * the contents of the same directory - exactly what network
6338 * file systems can do) although the server (Samba) could
6339 * still use it. For the short term we leave the worker
6340 * function ifdeffed out (below) until inotify is fixed
6341 * in the VFS to make it easier to plug in network file
6342 * system clients. If inotify turns out to be permanently
6343 * incompatible for network fs clients, we could instead simply
6344 * expose this config flag by adding a future cifs (and smb2) notify ioctl.
6345 */
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006346int CIFSSMBNotify(const unsigned int xid, struct cifs_tcon *tcon,
Steve French0eff0e22011-02-24 05:39:23 +00006347 const int notify_subdirs, const __u16 netfid,
6348 __u32 filter, struct file *pfile, int multishot,
6349 const struct nls_table *nls_codepage)
6350{
6351 int rc = 0;
6352 struct smb_com_transaction_change_notify_req *pSMB = NULL;
6353 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
6354 struct dir_notify_req *dnotify_req;
6355 int bytes_returned;
6356
6357 cFYI(1, "In CIFSSMBNotify for file handle %d", (int)netfid);
6358 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
6359 (void **) &pSMBr);
6360 if (rc)
6361 return rc;
6362
6363 pSMB->TotalParameterCount = 0 ;
6364 pSMB->TotalDataCount = 0;
6365 pSMB->MaxParameterCount = cpu_to_le32(2);
Jeff Laytonc974bef2011-10-11 06:41:32 -04006366 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Steve French0eff0e22011-02-24 05:39:23 +00006367 pSMB->MaxSetupCount = 4;
6368 pSMB->Reserved = 0;
6369 pSMB->ParameterOffset = 0;
6370 pSMB->DataCount = 0;
6371 pSMB->DataOffset = 0;
6372 pSMB->SetupCount = 4; /* single byte does not need le conversion */
6373 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
6374 pSMB->ParameterCount = pSMB->TotalParameterCount;
6375 if (notify_subdirs)
6376 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
6377 pSMB->Reserved2 = 0;
6378 pSMB->CompletionFilter = cpu_to_le32(filter);
6379 pSMB->Fid = netfid; /* file handle always le */
6380 pSMB->ByteCount = 0;
6381
6382 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6383 (struct smb_hdr *)pSMBr, &bytes_returned,
6384 CIFS_ASYNC_OP);
6385 if (rc) {
6386 cFYI(1, "Error in Notify = %d", rc);
6387 } else {
6388 /* Add file to outstanding requests */
6389 /* BB change to kmem cache alloc */
6390 dnotify_req = kmalloc(
6391 sizeof(struct dir_notify_req),
6392 GFP_KERNEL);
6393 if (dnotify_req) {
6394 dnotify_req->Pid = pSMB->hdr.Pid;
6395 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
6396 dnotify_req->Mid = pSMB->hdr.Mid;
6397 dnotify_req->Tid = pSMB->hdr.Tid;
6398 dnotify_req->Uid = pSMB->hdr.Uid;
6399 dnotify_req->netfid = netfid;
6400 dnotify_req->pfile = pfile;
6401 dnotify_req->filter = filter;
6402 dnotify_req->multishot = multishot;
6403 spin_lock(&GlobalMid_Lock);
6404 list_add_tail(&dnotify_req->lhead,
6405 &GlobalDnotifyReqList);
6406 spin_unlock(&GlobalMid_Lock);
6407 } else
6408 rc = -ENOMEM;
6409 }
6410 cifs_buf_release(pSMB);
6411 return rc;
6412}
6413#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */