blob: 01808eb3af47854d2b6cb95af2ac1af36628ffb5 [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 Layton99d86c8f2011-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 Shilovsky6d5786a2012-06-20 11:21:16 +0400951CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon,
952 const char *dirName, const struct nls_table *nls_codepage,
953 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954{
955 DELETE_DIRECTORY_REQ *pSMB = NULL;
956 DELETE_DIRECTORY_RSP *pSMBr = NULL;
957 int rc = 0;
958 int bytes_returned;
959 int name_len;
960
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) {
Steve Frenchacbbb762012-01-18 22:32:33 -0600969 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, dirName,
970 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971 name_len++; /* trailing null */
972 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700973 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974 name_len = strnlen(dirName, PATH_MAX);
975 name_len++; /* trailing null */
976 strncpy(pSMB->DirName, dirName, name_len);
977 }
978
979 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000980 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981 pSMB->ByteCount = cpu_to_le16(name_len + 1);
982 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
983 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400984 cifs_stats_inc(&tcon->stats.cifs_stats.num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000985 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000986 cFYI(1, "Error in RMDir = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987
988 cifs_buf_release(pSMB);
989 if (rc == -EAGAIN)
990 goto RmDirRetry;
991 return rc;
992}
993
994int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400995CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon,
Steve French737b7582005-04-28 22:41:06 -0700996 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997{
998 int rc = 0;
999 CREATE_DIRECTORY_REQ *pSMB = NULL;
1000 CREATE_DIRECTORY_RSP *pSMBr = NULL;
1001 int bytes_returned;
1002 int name_len;
1003
Joe Perchesb6b38f72010-04-21 03:50:45 +00001004 cFYI(1, "In CIFSSMBMkDir");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005MkDirRetry:
1006 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
1007 (void **) &pSMBr);
1008 if (rc)
1009 return rc;
1010
1011 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06001012 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
1013 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014 name_len++; /* trailing null */
1015 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -07001016 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 name_len = strnlen(name, PATH_MAX);
1018 name_len++; /* trailing null */
1019 strncpy(pSMB->DirName, name, name_len);
1020 }
1021
1022 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001023 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024 pSMB->ByteCount = cpu_to_le16(name_len + 1);
1025 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1026 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001027 cifs_stats_inc(&tcon->stats.cifs_stats.num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +00001028 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001029 cFYI(1, "Error in Mkdir = %d", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07001030
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031 cifs_buf_release(pSMB);
1032 if (rc == -EAGAIN)
1033 goto MkDirRetry;
1034 return rc;
1035}
1036
Steve French2dd29d32007-04-23 22:07:35 +00001037int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001038CIFSPOSIXCreate(const unsigned int xid, struct cifs_tcon *tcon,
1039 __u32 posix_flags, __u64 mode, __u16 *netfid,
1040 FILE_UNIX_BASIC_INFO *pRetData, __u32 *pOplock,
1041 const char *name, const struct nls_table *nls_codepage,
1042 int remap)
Steve French2dd29d32007-04-23 22:07:35 +00001043{
1044 TRANSACTION2_SPI_REQ *pSMB = NULL;
1045 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1046 int name_len;
1047 int rc = 0;
1048 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001049 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +00001050 OPEN_PSX_REQ *pdata;
1051 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +00001052
Joe Perchesb6b38f72010-04-21 03:50:45 +00001053 cFYI(1, "In POSIX Create");
Steve French2dd29d32007-04-23 22:07:35 +00001054PsxCreat:
1055 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1056 (void **) &pSMBr);
1057 if (rc)
1058 return rc;
1059
1060 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1061 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001062 cifsConvertToUTF16((__le16 *) pSMB->FileName, name,
1063 PATH_MAX, nls_codepage, remap);
Steve French2dd29d32007-04-23 22:07:35 +00001064 name_len++; /* trailing null */
1065 name_len *= 2;
1066 } else { /* BB improve the check for buffer overruns BB */
1067 name_len = strnlen(name, PATH_MAX);
1068 name_len++; /* trailing null */
1069 strncpy(pSMB->FileName, name, name_len);
1070 }
1071
1072 params = 6 + name_len;
1073 count = sizeof(OPEN_PSX_REQ);
1074 pSMB->MaxParameterCount = cpu_to_le16(2);
1075 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1076 pSMB->MaxSetupCount = 0;
1077 pSMB->Reserved = 0;
1078 pSMB->Flags = 0;
1079 pSMB->Timeout = 0;
1080 pSMB->Reserved2 = 0;
1081 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001082 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001083 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001084 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001085 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001086 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001087 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001088 pdata->OpenFlags = cpu_to_le32(*pOplock);
1089 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1090 pSMB->DataOffset = cpu_to_le16(offset);
1091 pSMB->SetupCount = 1;
1092 pSMB->Reserved3 = 0;
1093 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1094 byte_count = 3 /* pad */ + params + count;
1095
1096 pSMB->DataCount = cpu_to_le16(count);
1097 pSMB->ParameterCount = cpu_to_le16(params);
1098 pSMB->TotalDataCount = pSMB->DataCount;
1099 pSMB->TotalParameterCount = pSMB->ParameterCount;
1100 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1101 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001102 inc_rfc1001_len(pSMB, byte_count);
Steve French2dd29d32007-04-23 22:07:35 +00001103 pSMB->ByteCount = cpu_to_le16(byte_count);
1104 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1105 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1106 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001107 cFYI(1, "Posix create returned %d", rc);
Steve French2dd29d32007-04-23 22:07:35 +00001108 goto psx_create_err;
1109 }
1110
Joe Perchesb6b38f72010-04-21 03:50:45 +00001111 cFYI(1, "copying inode info");
Steve French2dd29d32007-04-23 22:07:35 +00001112 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1113
Jeff Layton820a8032011-05-04 08:05:26 -04001114 if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) {
Steve French2dd29d32007-04-23 22:07:35 +00001115 rc = -EIO; /* bad smb */
1116 goto psx_create_err;
1117 }
1118
1119 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001120 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001121 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001122
Steve French2dd29d32007-04-23 22:07:35 +00001123 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001124 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001125 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1126 /* Let caller know file was created so we can set the mode. */
1127 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001128 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001129 *pOplock |= CIFS_CREATE_ACTION;
1130 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001131 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1132 pRetData->Type = cpu_to_le32(-1); /* unknown */
Joe Perchesb6b38f72010-04-21 03:50:45 +00001133 cFYI(DBG2, "unknown type");
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001134 } else {
Jeff Layton820a8032011-05-04 08:05:26 -04001135 if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001136 + sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001137 cERROR(1, "Open response data too small");
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001138 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001139 goto psx_create_err;
1140 }
Steve French50c2f752007-07-13 00:33:32 +00001141 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001142 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001143 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001144 }
Steve French2dd29d32007-04-23 22:07:35 +00001145
1146psx_create_err:
1147 cifs_buf_release(pSMB);
1148
Steve French65bc98b2009-07-10 15:27:25 +00001149 if (posix_flags & SMB_O_DIRECTORY)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001150 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixmkdirs);
Steve French65bc98b2009-07-10 15:27:25 +00001151 else
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001152 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixopens);
Steve French2dd29d32007-04-23 22:07:35 +00001153
1154 if (rc == -EAGAIN)
1155 goto PsxCreat;
1156
Steve French50c2f752007-07-13 00:33:32 +00001157 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001158}
1159
Steve Frencha9d02ad2005-08-24 23:06:05 -07001160static __u16 convert_disposition(int disposition)
1161{
1162 __u16 ofun = 0;
1163
1164 switch (disposition) {
1165 case FILE_SUPERSEDE:
1166 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1167 break;
1168 case FILE_OPEN:
1169 ofun = SMBOPEN_OAPPEND;
1170 break;
1171 case FILE_CREATE:
1172 ofun = SMBOPEN_OCREATE;
1173 break;
1174 case FILE_OPEN_IF:
1175 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1176 break;
1177 case FILE_OVERWRITE:
1178 ofun = SMBOPEN_OTRUNC;
1179 break;
1180 case FILE_OVERWRITE_IF:
1181 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1182 break;
1183 default:
Joe Perchesb6b38f72010-04-21 03:50:45 +00001184 cFYI(1, "unknown disposition %d", disposition);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001185 ofun = SMBOPEN_OAPPEND; /* regular open */
1186 }
1187 return ofun;
1188}
1189
Jeff Layton35fc37d2008-05-14 10:22:03 -07001190static int
1191access_flags_to_smbopen_mode(const int access_flags)
1192{
1193 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1194
1195 if (masked_flags == GENERIC_READ)
1196 return SMBOPEN_READ;
1197 else if (masked_flags == GENERIC_WRITE)
1198 return SMBOPEN_WRITE;
1199
1200 /* just go for read/write */
1201 return SMBOPEN_READWRITE;
1202}
1203
Steve Frencha9d02ad2005-08-24 23:06:05 -07001204int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001205SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001206 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001207 const int access_flags, const int create_options, __u16 *netfid,
1208 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001209 const struct nls_table *nls_codepage, int remap)
1210{
1211 int rc = -EACCES;
1212 OPENX_REQ *pSMB = NULL;
1213 OPENX_RSP *pSMBr = NULL;
1214 int bytes_returned;
1215 int name_len;
1216 __u16 count;
1217
1218OldOpenRetry:
1219 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1220 (void **) &pSMBr);
1221 if (rc)
1222 return rc;
1223
1224 pSMB->AndXCommand = 0xFF; /* none */
1225
1226 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1227 count = 1; /* account for one byte pad to word boundary */
1228 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001229 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1230 fileName, PATH_MAX, nls_codepage, remap);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001231 name_len++; /* trailing null */
1232 name_len *= 2;
1233 } else { /* BB improve check for buffer overruns BB */
1234 count = 0; /* no pad */
1235 name_len = strnlen(fileName, PATH_MAX);
1236 name_len++; /* trailing null */
1237 strncpy(pSMB->fileName, fileName, name_len);
1238 }
1239 if (*pOplock & REQ_OPLOCK)
1240 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001241 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001242 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001243
Steve Frencha9d02ad2005-08-24 23:06:05 -07001244 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001245 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001246 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1247 /* set file as system file if special file such
1248 as fifo and server expecting SFU style and
1249 no Unix extensions */
1250
Steve French790fe572007-07-07 19:25:05 +00001251 if (create_options & CREATE_OPTION_SPECIAL)
1252 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001253 else /* BB FIXME BB */
1254 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001255
Jeff Layton67750fb2008-05-09 22:28:02 +00001256 if (create_options & CREATE_OPTION_READONLY)
1257 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001258
1259 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001260/* pSMB->CreateOptions = cpu_to_le32(create_options &
1261 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001262 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001263
1264 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001265 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001266 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001267 inc_rfc1001_len(pSMB, count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001268
1269 pSMB->ByteCount = cpu_to_le16(count);
1270 /* long_op set to 1 to allow for oplock break timeouts */
1271 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001272 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001273 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001274 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001275 cFYI(1, "Error in Open = %d", rc);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001276 } else {
1277 /* BB verify if wct == 15 */
1278
Steve French582d21e2008-05-13 04:54:12 +00001279/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001280
1281 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1282 /* Let caller know file was created so we can set the mode. */
1283 /* Do we care about the CreateAction in any other cases? */
1284 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001285/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001286 *pOplock |= CIFS_CREATE_ACTION; */
1287 /* BB FIXME END */
1288
Steve French790fe572007-07-07 19:25:05 +00001289 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001290 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1291 pfile_info->LastAccessTime = 0; /* BB fixme */
1292 pfile_info->LastWriteTime = 0; /* BB fixme */
1293 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001294 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001295 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001296 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001297 pfile_info->AllocationSize =
1298 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1299 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001300 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001301 pfile_info->DeletePending = 0;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001302 }
1303 }
1304
1305 cifs_buf_release(pSMB);
1306 if (rc == -EAGAIN)
1307 goto OldOpenRetry;
1308 return rc;
1309}
1310
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001312CIFSSMBOpen(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001314 const int access_flags, const int create_options, __u16 *netfid,
1315 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001316 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317{
1318 int rc = -EACCES;
1319 OPEN_REQ *pSMB = NULL;
1320 OPEN_RSP *pSMBr = NULL;
1321 int bytes_returned;
1322 int name_len;
1323 __u16 count;
1324
1325openRetry:
1326 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1327 (void **) &pSMBr);
1328 if (rc)
1329 return rc;
1330
1331 pSMB->AndXCommand = 0xFF; /* none */
1332
1333 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1334 count = 1; /* account for one byte pad to word boundary */
1335 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001336 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1337 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338 name_len++; /* trailing null */
1339 name_len *= 2;
1340 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001341 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342 count = 0; /* no pad */
1343 name_len = strnlen(fileName, PATH_MAX);
1344 name_len++; /* trailing null */
1345 pSMB->NameLength = cpu_to_le16(name_len);
1346 strncpy(pSMB->fileName, fileName, name_len);
1347 }
1348 if (*pOplock & REQ_OPLOCK)
1349 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001350 else if (*pOplock & REQ_BATCHOPLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1353 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -07001354 /* set file as system file if special file such
1355 as fifo and server expecting SFU style and
1356 no Unix extensions */
Steve French790fe572007-07-07 19:25:05 +00001357 if (create_options & CREATE_OPTION_SPECIAL)
Steve Frencheda3c0292005-07-21 15:20:28 -07001358 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1359 else
1360 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Jeff Layton67750fb2008-05-09 22:28:02 +00001361
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362 /* XP does not handle ATTR_POSIX_SEMANTICS */
1363 /* but it helps speed up case sensitive checks for other
1364 servers such as Samba */
1365 if (tcon->ses->capabilities & CAP_UNIX)
1366 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1367
Jeff Layton67750fb2008-05-09 22:28:02 +00001368 if (create_options & CREATE_OPTION_READONLY)
1369 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1370
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1372 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -07001373 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001374 /* BB Expirement with various impersonation levels and verify */
1375 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376 pSMB->SecurityFlags =
1377 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1378
1379 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001380 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381
1382 pSMB->ByteCount = cpu_to_le16(count);
1383 /* long_op set to 1 to allow for oplock break timeouts */
1384 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001385 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001386 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001388 cFYI(1, "Error in Open = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389 } else {
Steve French09d1db52005-04-28 22:41:08 -07001390 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1392 /* Let caller know file was created so we can set the mode. */
1393 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001394 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve French50c2f752007-07-13 00:33:32 +00001395 *pOplock |= CIFS_CREATE_ACTION;
Steve French790fe572007-07-07 19:25:05 +00001396 if (pfile_info) {
Steve French61e74802008-12-03 00:57:54 +00001397 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1398 36 /* CreationTime to Attributes */);
1399 /* the file_info buf is endian converted by caller */
1400 pfile_info->AllocationSize = pSMBr->AllocationSize;
1401 pfile_info->EndOfFile = pSMBr->EndOfFile;
1402 pfile_info->NumberOfLinks = cpu_to_le32(1);
1403 pfile_info->DeletePending = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001406
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407 cifs_buf_release(pSMB);
1408 if (rc == -EAGAIN)
1409 goto openRetry;
1410 return rc;
1411}
1412
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001413/*
1414 * Discard any remaining data in the current SMB. To do this, we borrow the
1415 * current bigbuf.
1416 */
1417static int
1418cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1419{
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001420 unsigned int rfclen = get_rfc1002_length(server->smallbuf);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001421 int remaining = rfclen + 4 - server->total_read;
1422 struct cifs_readdata *rdata = mid->callback_data;
1423
1424 while (remaining > 0) {
1425 int length;
1426
1427 length = cifs_read_from_socket(server, server->bigbuf,
1428 min_t(unsigned int, remaining,
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001429 CIFSMaxBufSize + MAX_HEADER_SIZE(server)));
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001430 if (length < 0)
1431 return length;
1432 server->total_read += length;
1433 remaining -= length;
1434 }
1435
1436 dequeue_mid(mid, rdata->result);
1437 return 0;
1438}
1439
1440static int
1441cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1442{
1443 int length, len;
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001444 unsigned int data_offset, data_len;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001445 struct cifs_readdata *rdata = mid->callback_data;
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001446 char *buf = server->smallbuf;
1447 unsigned int buflen = get_rfc1002_length(buf) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001448
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001449 cFYI(1, "%s: mid=%llu offset=%llu bytes=%u", __func__,
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001450 mid->mid, rdata->offset, rdata->bytes);
1451
1452 /*
1453 * read the rest of READ_RSP header (sans Data array), or whatever we
1454 * can if there's not enough data. At this point, we've read down to
1455 * the Mid.
1456 */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001457 len = min_t(unsigned int, buflen, server->vals->read_rsp_size) -
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001458 HEADER_SIZE(server) + 1;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001459
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001460 rdata->iov[0].iov_base = buf + HEADER_SIZE(server) - 1;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001461 rdata->iov[0].iov_len = len;
1462
1463 length = cifs_readv_from_socket(server, rdata->iov, 1, len);
1464 if (length < 0)
1465 return length;
1466 server->total_read += length;
1467
1468 /* Was the SMB read successful? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001469 rdata->result = server->ops->map_error(buf, false);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001470 if (rdata->result != 0) {
1471 cFYI(1, "%s: server returned error %d", __func__,
1472 rdata->result);
1473 return cifs_readv_discard(server, mid);
1474 }
1475
1476 /* Is there enough to get to the rest of the READ_RSP header? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001477 if (server->total_read < server->vals->read_rsp_size) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001478 cFYI(1, "%s: server returned short header. got=%u expected=%zu",
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001479 __func__, server->total_read,
1480 server->vals->read_rsp_size);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001481 rdata->result = -EIO;
1482 return cifs_readv_discard(server, mid);
1483 }
1484
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001485 data_offset = server->ops->read_data_offset(buf) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001486 if (data_offset < server->total_read) {
1487 /*
1488 * win2k8 sometimes sends an offset of 0 when the read
1489 * is beyond the EOF. Treat it as if the data starts just after
1490 * the header.
1491 */
1492 cFYI(1, "%s: data offset (%u) inside read response header",
1493 __func__, data_offset);
1494 data_offset = server->total_read;
1495 } else if (data_offset > MAX_CIFS_SMALL_BUFFER_SIZE) {
1496 /* data_offset is beyond the end of smallbuf */
1497 cFYI(1, "%s: data offset (%u) beyond end of smallbuf",
1498 __func__, data_offset);
1499 rdata->result = -EIO;
1500 return cifs_readv_discard(server, mid);
1501 }
1502
1503 cFYI(1, "%s: total_read=%u data_offset=%u", __func__,
1504 server->total_read, data_offset);
1505
1506 len = data_offset - server->total_read;
1507 if (len > 0) {
1508 /* read any junk before data into the rest of smallbuf */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001509 rdata->iov[0].iov_base = buf + server->total_read;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001510 rdata->iov[0].iov_len = len;
1511 length = cifs_readv_from_socket(server, rdata->iov, 1, len);
1512 if (length < 0)
1513 return length;
1514 server->total_read += length;
1515 }
1516
1517 /* set up first iov for signature check */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001518 rdata->iov[0].iov_base = buf;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001519 rdata->iov[0].iov_len = server->total_read;
1520 cFYI(1, "0: iov_base=%p iov_len=%zu",
1521 rdata->iov[0].iov_base, rdata->iov[0].iov_len);
1522
1523 /* how much data is in the response? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001524 data_len = server->ops->read_data_length(buf);
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001525 if (data_offset + data_len > buflen) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001526 /* data_len is corrupt -- discard frame */
1527 rdata->result = -EIO;
1528 return cifs_readv_discard(server, mid);
1529 }
1530
1531 /* marshal up the page array */
Jeff Layton3cf003c2012-07-11 09:09:36 -04001532 cifs_kmap_lock();
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001533 len = rdata->marshal_iov(rdata, data_len);
Jeff Layton3cf003c2012-07-11 09:09:36 -04001534 cifs_kmap_unlock();
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001535 data_len -= len;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001536
1537 /* issue the read if we have any iovecs left to fill */
1538 if (rdata->nr_iov > 1) {
1539 length = cifs_readv_from_socket(server, &rdata->iov[1],
1540 rdata->nr_iov - 1, len);
1541 if (length < 0)
1542 return length;
1543 server->total_read += length;
1544 } else {
1545 length = 0;
1546 }
1547
1548 rdata->bytes = length;
1549
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001550 cFYI(1, "total_read=%u buflen=%u remaining=%u", server->total_read,
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001551 buflen, data_len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001552
1553 /* discard anything left over */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001554 if (server->total_read < buflen)
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001555 return cifs_readv_discard(server, mid);
1556
1557 dequeue_mid(mid, false);
1558 return length;
1559}
1560
1561static void
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001562cifs_readv_callback(struct mid_q_entry *mid)
1563{
1564 struct cifs_readdata *rdata = mid->callback_data;
1565 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1566 struct TCP_Server_Info *server = tcon->ses->server;
1567
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001568 cFYI(1, "%s: mid=%llu state=%d result=%d bytes=%u", __func__,
1569 mid->mid, mid->mid_state, rdata->result, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001570
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001571 switch (mid->mid_state) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001572 case MID_RESPONSE_RECEIVED:
1573 /* result already set, check signature */
1574 if (server->sec_mode &
1575 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
1576 if (cifs_verify_signature(rdata->iov, rdata->nr_iov,
1577 server, mid->sequence_number + 1))
1578 cERROR(1, "Unexpected SMB signature");
1579 }
1580 /* FIXME: should this be counted toward the initiating task? */
1581 task_io_account_read(rdata->bytes);
1582 cifs_stats_bytes_read(tcon, rdata->bytes);
1583 break;
1584 case MID_REQUEST_SUBMITTED:
1585 case MID_RETRY_NEEDED:
1586 rdata->result = -EAGAIN;
1587 break;
1588 default:
1589 rdata->result = -EIO;
1590 }
1591
Jeff Laytonda472fc2012-03-23 14:40:53 -04001592 queue_work(cifsiod_wq, &rdata->work);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001593 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04001594 add_credits(server, 1, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001595}
1596
1597/* cifs_async_readv - send an async write, and set up mid to handle result */
1598int
1599cifs_async_readv(struct cifs_readdata *rdata)
1600{
1601 int rc;
1602 READ_REQ *smb = NULL;
1603 int wct;
1604 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1605
1606 cFYI(1, "%s: offset=%llu bytes=%u", __func__,
1607 rdata->offset, rdata->bytes);
1608
1609 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1610 wct = 12;
1611 else {
1612 wct = 10; /* old style read */
1613 if ((rdata->offset >> 32) > 0) {
1614 /* can not handle this big offset for old */
1615 return -EIO;
1616 }
1617 }
1618
1619 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **)&smb);
1620 if (rc)
1621 return rc;
1622
1623 smb->hdr.Pid = cpu_to_le16((__u16)rdata->pid);
1624 smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16));
1625
1626 smb->AndXCommand = 0xFF; /* none */
1627 smb->Fid = rdata->cfile->netfid;
1628 smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF);
1629 if (wct == 12)
1630 smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32);
1631 smb->Remaining = 0;
1632 smb->MaxCount = cpu_to_le16(rdata->bytes & 0xFFFF);
1633 smb->MaxCountHigh = cpu_to_le32(rdata->bytes >> 16);
1634 if (wct == 12)
1635 smb->ByteCount = 0;
1636 else {
1637 /* old style read */
1638 struct smb_com_readx_req *smbr =
1639 (struct smb_com_readx_req *)smb;
1640 smbr->ByteCount = 0;
1641 }
1642
1643 /* 4 for RFC1001 length + 1 for BCC */
1644 rdata->iov[0].iov_base = smb;
1645 rdata->iov[0].iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
1646
Jeff Layton6993f742012-05-16 07:13:17 -04001647 kref_get(&rdata->refcount);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001648 rc = cifs_call_async(tcon->ses->server, rdata->iov, 1,
1649 cifs_readv_receive, cifs_readv_callback,
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04001650 rdata, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001651
1652 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001653 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Jeff Layton6993f742012-05-16 07:13:17 -04001654 else
1655 kref_put(&rdata->refcount, cifs_readdata_release);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001656
1657 cifs_small_buf_release(smb);
1658 return rc;
1659}
1660
Linus Torvalds1da177e2005-04-16 15:20:36 -07001661int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001662CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
1663 unsigned int *nbytes, char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664{
1665 int rc = -EACCES;
1666 READ_REQ *pSMB = NULL;
1667 READ_RSP *pSMBr = NULL;
1668 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001669 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001670 int resp_buf_type = 0;
1671 struct kvec iov[1];
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001672 __u32 pid = io_parms->pid;
1673 __u16 netfid = io_parms->netfid;
1674 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001675 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001676 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677
Joe Perchesb6b38f72010-04-21 03:50:45 +00001678 cFYI(1, "Reading %d bytes on fid %d", count, netfid);
Steve French790fe572007-07-07 19:25:05 +00001679 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001680 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001681 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001682 wct = 10; /* old style read */
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001683 if ((offset >> 32) > 0) {
Steve French4c3130e2008-12-09 00:28:16 +00001684 /* can not handle this big offset for old */
1685 return -EIO;
1686 }
1687 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001688
1689 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001690 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691 if (rc)
1692 return rc;
1693
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001694 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1695 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1696
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697 /* tcon and ses pointer are checked in smb_init */
1698 if (tcon->ses->server == NULL)
1699 return -ECONNABORTED;
1700
Steve Frenchec637e32005-12-12 20:53:18 -08001701 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702 pSMB->Fid = netfid;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001703 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001704 if (wct == 12)
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001705 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001706
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707 pSMB->Remaining = 0;
1708 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1709 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001710 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001711 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1712 else {
1713 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001714 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001715 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001716 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001717 }
Steve Frenchec637e32005-12-12 20:53:18 -08001718
1719 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001720 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve Frencha761ac52007-10-18 21:45:27 +00001721 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Jeff Layton77499812011-01-11 07:24:23 -05001722 &resp_buf_type, CIFS_LOG_ERROR);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001723 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001724 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001726 cERROR(1, "Send error in read = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727 } else {
1728 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1729 data_length = data_length << 16;
1730 data_length += le16_to_cpu(pSMBr->DataLength);
1731 *nbytes = data_length;
1732
1733 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001734 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735 || (data_length > count)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001736 cFYI(1, "bad length %d for count %d",
1737 data_length, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001738 rc = -EIO;
1739 *nbytes = 0;
1740 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001741 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001742 le16_to_cpu(pSMBr->DataOffset);
1743/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001744 cERROR(1, "Faulting on read rc = %d",rc);
Steve French50c2f752007-07-13 00:33:32 +00001745 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001746 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001747 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001748 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749 }
1750 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751
Steve French4b8f9302006-02-26 16:41:18 +00001752/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001753 if (*buf) {
1754 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001755 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001756 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001757 cifs_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001758 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001759 /* return buffer to caller to free */
1760 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001761 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001762 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001763 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001764 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001765 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001766
1767 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001768 since file handle passed in no longer valid */
1769 return rc;
1770}
1771
Steve Frenchec637e32005-12-12 20:53:18 -08001772
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001774CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001775 unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001776 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777{
1778 int rc = -EACCES;
1779 WRITE_REQ *pSMB = NULL;
1780 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001781 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001782 __u32 bytes_sent;
1783 __u16 byte_count;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001784 __u32 pid = io_parms->pid;
1785 __u16 netfid = io_parms->netfid;
1786 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001787 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001788 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001789
Steve Frencha24e2d72010-04-03 17:20:21 +00001790 *nbytes = 0;
1791
Joe Perchesb6b38f72010-04-21 03:50:45 +00001792 /* cFYI(1, "write at %lld %d bytes", offset, count);*/
Steve French790fe572007-07-07 19:25:05 +00001793 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001794 return -ECONNABORTED;
1795
Steve French790fe572007-07-07 19:25:05 +00001796 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001797 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001798 else {
Steve French1c955182005-08-30 20:58:07 -07001799 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001800 if ((offset >> 32) > 0) {
1801 /* can not handle big offset for old srv */
1802 return -EIO;
1803 }
1804 }
Steve French1c955182005-08-30 20:58:07 -07001805
1806 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807 (void **) &pSMBr);
1808 if (rc)
1809 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001810
1811 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1812 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1813
Linus Torvalds1da177e2005-04-16 15:20:36 -07001814 /* tcon and ses pointer are checked in smb_init */
1815 if (tcon->ses->server == NULL)
1816 return -ECONNABORTED;
1817
1818 pSMB->AndXCommand = 0xFF; /* none */
1819 pSMB->Fid = netfid;
1820 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001821 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001822 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001823
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824 pSMB->Reserved = 0xFFFFFFFF;
1825 pSMB->WriteMode = 0;
1826 pSMB->Remaining = 0;
1827
Steve French50c2f752007-07-13 00:33:32 +00001828 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001829 can send more if LARGE_WRITE_X capability returned by the server and if
1830 our buffer is big enough or if we convert to iovecs on socket writes
1831 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001832 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001833 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1834 } else {
1835 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1836 & ~0xFF;
1837 }
1838
1839 if (bytes_sent > count)
1840 bytes_sent = count;
1841 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001842 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001843 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001844 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001845 else if (ubuf) {
1846 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001847 cifs_buf_release(pSMB);
1848 return -EFAULT;
1849 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001850 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001851 /* No buffer */
1852 cifs_buf_release(pSMB);
1853 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001854 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001855 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001856 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001857 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001858 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001859
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1861 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001862 inc_rfc1001_len(pSMB, byte_count);
Steve French1c955182005-08-30 20:58:07 -07001863
Steve French790fe572007-07-07 19:25:05 +00001864 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001865 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001866 else { /* old style write has byte count 4 bytes earlier
1867 so 4 bytes pad */
1868 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001869 (struct smb_com_writex_req *)pSMB;
1870 pSMBW->ByteCount = cpu_to_le16(byte_count);
1871 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872
1873 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1874 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001875 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00001877 cFYI(1, "Send error in write = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001878 } else {
1879 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1880 *nbytes = (*nbytes) << 16;
1881 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301882
1883 /*
1884 * Mask off high 16 bits when bytes written as returned by the
1885 * server is greater than bytes requested by the client. Some
1886 * OS/2 servers are known to set incorrect CountHigh values.
1887 */
1888 if (*nbytes > count)
1889 *nbytes &= 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890 }
1891
1892 cifs_buf_release(pSMB);
1893
Steve French50c2f752007-07-13 00:33:32 +00001894 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895 since file handle passed in no longer valid */
1896
1897 return rc;
1898}
1899
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001900void
1901cifs_writedata_release(struct kref *refcount)
1902{
1903 struct cifs_writedata *wdata = container_of(refcount,
1904 struct cifs_writedata, refcount);
1905
1906 if (wdata->cfile)
1907 cifsFileInfo_put(wdata->cfile);
1908
1909 kfree(wdata);
1910}
1911
1912/*
1913 * Write failed with a retryable error. Resend the write request. It's also
1914 * possible that the page was redirtied so re-clean the page.
1915 */
1916static void
1917cifs_writev_requeue(struct cifs_writedata *wdata)
1918{
1919 int i, rc;
1920 struct inode *inode = wdata->cfile->dentry->d_inode;
1921
1922 for (i = 0; i < wdata->nr_pages; i++) {
1923 lock_page(wdata->pages[i]);
1924 clear_page_dirty_for_io(wdata->pages[i]);
1925 }
1926
1927 do {
1928 rc = cifs_async_writev(wdata);
1929 } while (rc == -EAGAIN);
1930
1931 for (i = 0; i < wdata->nr_pages; i++) {
1932 if (rc != 0)
1933 SetPageError(wdata->pages[i]);
1934 unlock_page(wdata->pages[i]);
1935 }
1936
1937 mapping_set_error(inode->i_mapping, rc);
1938 kref_put(&wdata->refcount, cifs_writedata_release);
1939}
1940
Jeff Laytonc2e87642012-03-23 14:40:55 -04001941void
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001942cifs_writev_complete(struct work_struct *work)
1943{
1944 struct cifs_writedata *wdata = container_of(work,
1945 struct cifs_writedata, work);
1946 struct inode *inode = wdata->cfile->dentry->d_inode;
1947 int i = 0;
1948
1949 if (wdata->result == 0) {
Jeff Layton597b0272012-03-23 14:40:56 -04001950 spin_lock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001951 cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
Jeff Layton597b0272012-03-23 14:40:56 -04001952 spin_unlock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001953 cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
1954 wdata->bytes);
1955 } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
1956 return cifs_writev_requeue(wdata);
1957
1958 for (i = 0; i < wdata->nr_pages; i++) {
1959 struct page *page = wdata->pages[i];
1960 if (wdata->result == -EAGAIN)
1961 __set_page_dirty_nobuffers(page);
1962 else if (wdata->result < 0)
1963 SetPageError(page);
1964 end_page_writeback(page);
1965 page_cache_release(page);
1966 }
1967 if (wdata->result != -EAGAIN)
1968 mapping_set_error(inode->i_mapping, wdata->result);
1969 kref_put(&wdata->refcount, cifs_writedata_release);
1970}
1971
1972struct cifs_writedata *
Jeff Laytonc2e87642012-03-23 14:40:55 -04001973cifs_writedata_alloc(unsigned int nr_pages, work_func_t complete)
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001974{
1975 struct cifs_writedata *wdata;
1976
1977 /* this would overflow */
1978 if (nr_pages == 0) {
1979 cERROR(1, "%s: called with nr_pages == 0!", __func__);
1980 return NULL;
1981 }
1982
1983 /* writedata + number of page pointers */
1984 wdata = kzalloc(sizeof(*wdata) +
1985 sizeof(struct page *) * (nr_pages - 1), GFP_NOFS);
1986 if (wdata != NULL) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001987 kref_init(&wdata->refcount);
Jeff Laytonda82f7e2012-03-23 14:40:56 -04001988 INIT_LIST_HEAD(&wdata->list);
1989 init_completion(&wdata->done);
1990 INIT_WORK(&wdata->work, complete);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001991 }
1992 return wdata;
1993}
1994
1995/*
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001996 * Check the mid_state and signature on received buffer (if any), and queue the
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001997 * workqueue completion task.
1998 */
1999static void
2000cifs_writev_callback(struct mid_q_entry *mid)
2001{
2002 struct cifs_writedata *wdata = mid->callback_data;
Steve French96daf2b2011-05-27 04:34:02 +00002003 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002004 unsigned int written;
2005 WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
2006
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04002007 switch (mid->mid_state) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002008 case MID_RESPONSE_RECEIVED:
2009 wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
2010 if (wdata->result != 0)
2011 break;
2012
2013 written = le16_to_cpu(smb->CountHigh);
2014 written <<= 16;
2015 written += le16_to_cpu(smb->Count);
2016 /*
2017 * Mask off high 16 bits when bytes written as returned
2018 * by the server is greater than bytes requested by the
2019 * client. OS/2 servers are known to set incorrect
2020 * CountHigh values.
2021 */
2022 if (written > wdata->bytes)
2023 written &= 0xFFFF;
2024
2025 if (written < wdata->bytes)
2026 wdata->result = -ENOSPC;
2027 else
2028 wdata->bytes = written;
2029 break;
2030 case MID_REQUEST_SUBMITTED:
2031 case MID_RETRY_NEEDED:
2032 wdata->result = -EAGAIN;
2033 break;
2034 default:
2035 wdata->result = -EIO;
2036 break;
2037 }
2038
Jeff Laytonda472fc2012-03-23 14:40:53 -04002039 queue_work(cifsiod_wq, &wdata->work);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002040 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002041 add_credits(tcon->ses->server, 1, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002042}
2043
2044/* cifs_async_writev - send an async write, and set up mid to handle result */
2045int
2046cifs_async_writev(struct cifs_writedata *wdata)
2047{
2048 int i, rc = -EACCES;
2049 WRITE_REQ *smb = NULL;
2050 int wct;
Steve French96daf2b2011-05-27 04:34:02 +00002051 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002052 struct kvec *iov = NULL;
2053
2054 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
2055 wct = 14;
2056 } else {
2057 wct = 12;
2058 if (wdata->offset >> 32 > 0) {
2059 /* can not handle big offset for old srv */
2060 return -EIO;
2061 }
2062 }
2063
2064 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
2065 if (rc)
2066 goto async_writev_out;
2067
2068 /* 1 iov per page + 1 for header */
2069 iov = kzalloc((wdata->nr_pages + 1) * sizeof(*iov), GFP_NOFS);
2070 if (iov == NULL) {
2071 rc = -ENOMEM;
2072 goto async_writev_out;
2073 }
2074
Jeff Laytonfe5f5d22012-03-23 14:40:55 -04002075 smb->hdr.Pid = cpu_to_le16((__u16)wdata->pid);
2076 smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16));
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002077
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002078 smb->AndXCommand = 0xFF; /* none */
2079 smb->Fid = wdata->cfile->netfid;
2080 smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
2081 if (wct == 14)
2082 smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
2083 smb->Reserved = 0xFFFFFFFF;
2084 smb->WriteMode = 0;
2085 smb->Remaining = 0;
2086
2087 smb->DataOffset =
2088 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
2089
2090 /* 4 for RFC1001 length + 1 for BCC */
2091 iov[0].iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4 + 1;
2092 iov[0].iov_base = smb;
2093
Jeff Laytone9492872012-03-23 14:40:56 -04002094 /*
2095 * This function should marshal up the page array into the kvec
2096 * array, reserving [0] for the header. It should kmap the pages
2097 * and set the iov_len properly for each one. It may also set
2098 * wdata->bytes too.
2099 */
Jeff Layton3cf003c2012-07-11 09:09:36 -04002100 cifs_kmap_lock();
Jeff Laytone9492872012-03-23 14:40:56 -04002101 wdata->marshal_iov(iov, wdata);
Jeff Layton3cf003c2012-07-11 09:09:36 -04002102 cifs_kmap_unlock();
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002103
2104 cFYI(1, "async write at %llu %u bytes", wdata->offset, wdata->bytes);
2105
2106 smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
2107 smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16);
2108
2109 if (wct == 14) {
2110 inc_rfc1001_len(&smb->hdr, wdata->bytes + 1);
2111 put_bcc(wdata->bytes + 1, &smb->hdr);
2112 } else {
2113 /* wct == 12 */
2114 struct smb_com_writex_req *smbw =
2115 (struct smb_com_writex_req *)smb;
2116 inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
2117 put_bcc(wdata->bytes + 5, &smbw->hdr);
2118 iov[0].iov_len += 4; /* pad bigger by four bytes */
2119 }
2120
2121 kref_get(&wdata->refcount);
2122 rc = cifs_call_async(tcon->ses->server, iov, wdata->nr_pages + 1,
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002123 NULL, cifs_writev_callback, wdata, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002124
2125 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002126 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002127 else
2128 kref_put(&wdata->refcount, cifs_writedata_release);
2129
2130 /* send is done, unmap pages */
2131 for (i = 0; i < wdata->nr_pages; i++)
2132 kunmap(wdata->pages[i]);
2133
2134async_writev_out:
2135 cifs_small_buf_release(smb);
2136 kfree(iov);
2137 return rc;
2138}
2139
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002140int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002141CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002142 unsigned int *nbytes, struct kvec *iov, int n_vec,
2143 const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002144{
2145 int rc = -EACCES;
2146 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08002147 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002148 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08002149 int resp_buf_type = 0;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002150 __u32 pid = io_parms->pid;
2151 __u16 netfid = io_parms->netfid;
2152 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00002153 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002154 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002155
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04002156 *nbytes = 0;
2157
Joe Perchesb6b38f72010-04-21 03:50:45 +00002158 cFYI(1, "write2 at %lld %d bytes", (long long)offset, count);
Steve Frenchff7feac2005-11-15 16:45:16 -08002159
Steve French4c3130e2008-12-09 00:28:16 +00002160 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07002161 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00002162 } else {
Steve French8cc64c62005-10-03 13:49:43 -07002163 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00002164 if ((offset >> 32) > 0) {
2165 /* can not handle big offset for old srv */
2166 return -EIO;
2167 }
2168 }
Steve French8cc64c62005-10-03 13:49:43 -07002169 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002170 if (rc)
2171 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002172
2173 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
2174 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
2175
Linus Torvalds1da177e2005-04-16 15:20:36 -07002176 /* tcon and ses pointer are checked in smb_init */
2177 if (tcon->ses->server == NULL)
2178 return -ECONNABORTED;
2179
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002180 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002181 pSMB->Fid = netfid;
2182 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00002183 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002184 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002185 pSMB->Reserved = 0xFFFFFFFF;
2186 pSMB->WriteMode = 0;
2187 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002188
Linus Torvalds1da177e2005-04-16 15:20:36 -07002189 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00002190 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002191
Steve French3e844692005-10-03 13:37:24 -07002192 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
2193 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002194 /* header + 1 byte pad */
2195 smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
Steve French790fe572007-07-07 19:25:05 +00002196 if (wct == 14)
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002197 inc_rfc1001_len(pSMB, count + 1);
Steve French8cc64c62005-10-03 13:49:43 -07002198 else /* wct == 12 */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002199 inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
Steve French790fe572007-07-07 19:25:05 +00002200 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002201 pSMB->ByteCount = cpu_to_le16(count + 1);
2202 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00002203 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07002204 (struct smb_com_writex_req *)pSMB;
2205 pSMBW->ByteCount = cpu_to_le16(count + 5);
2206 }
Steve French3e844692005-10-03 13:37:24 -07002207 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00002208 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08002209 iov[0].iov_len = smb_hdr_len + 4;
2210 else /* wct == 12 pad bigger by four bytes */
2211 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00002212
Steve French3e844692005-10-03 13:37:24 -07002213
Steve Frenchec637e32005-12-12 20:53:18 -08002214 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French133672e2007-11-13 22:41:37 +00002215 long_op);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002216 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002217 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002218 cFYI(1, "Send error Write2 = %d", rc);
Steve French790fe572007-07-07 19:25:05 +00002219 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08002220 /* presumably this can not happen, but best to be safe */
2221 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002222 } else {
Steve Frenchad7a2922008-02-07 23:25:02 +00002223 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002224 *nbytes = le16_to_cpu(pSMBr->CountHigh);
2225 *nbytes = (*nbytes) << 16;
2226 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05302227
2228 /*
2229 * Mask off high 16 bits when bytes written as returned by the
2230 * server is greater than bytes requested by the client. OS/2
2231 * servers are known to set incorrect CountHigh values.
2232 */
2233 if (*nbytes > count)
2234 *nbytes &= 0xFFFF;
Steve French50c2f752007-07-13 00:33:32 +00002235 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002236
Steve French4b8f9302006-02-26 16:41:18 +00002237/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00002238 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002239 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00002240 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002241 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002242
Steve French50c2f752007-07-13 00:33:32 +00002243 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002244 since file handle passed in no longer valid */
2245
2246 return rc;
2247}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002248
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002249int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon,
2250 const __u16 netfid, const __u8 lock_type, const __u32 num_unlock,
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002251 const __u32 num_lock, LOCKING_ANDX_RANGE *buf)
2252{
2253 int rc = 0;
2254 LOCK_REQ *pSMB = NULL;
2255 struct kvec iov[2];
2256 int resp_buf_type;
2257 __u16 count;
2258
2259 cFYI(1, "cifs_lockv num lock %d num unlock %d", num_lock, num_unlock);
2260
2261 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2262 if (rc)
2263 return rc;
2264
2265 pSMB->Timeout = 0;
2266 pSMB->NumberOfLocks = cpu_to_le16(num_lock);
2267 pSMB->NumberOfUnlocks = cpu_to_le16(num_unlock);
2268 pSMB->LockType = lock_type;
2269 pSMB->AndXCommand = 0xFF; /* none */
2270 pSMB->Fid = netfid; /* netfid stays le */
2271
2272 count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2273 inc_rfc1001_len(pSMB, count);
2274 pSMB->ByteCount = cpu_to_le16(count);
2275
2276 iov[0].iov_base = (char *)pSMB;
2277 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 -
2278 (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2279 iov[1].iov_base = (char *)buf;
2280 iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2281
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002282 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002283 rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP);
2284 if (rc)
2285 cFYI(1, "Send error in cifs_lockv = %d", rc);
2286
2287 return rc;
2288}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002289
Linus Torvalds1da177e2005-04-16 15:20:36 -07002290int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002291CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002292 const __u16 smb_file_id, const __u32 netpid, const __u64 len,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002293 const __u64 offset, const __u32 numUnlock,
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002294 const __u32 numLock, const __u8 lockType,
2295 const bool waitFlag, const __u8 oplock_level)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002296{
2297 int rc = 0;
2298 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002299/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002300 int bytes_returned;
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002301 int flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002302 __u16 count;
2303
Joe Perchesb6b38f72010-04-21 03:50:45 +00002304 cFYI(1, "CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock);
Steve French46810cb2005-04-28 22:41:09 -07002305 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2306
Linus Torvalds1da177e2005-04-16 15:20:36 -07002307 if (rc)
2308 return rc;
2309
Steve French790fe572007-07-07 19:25:05 +00002310 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002311 /* no response expected */
2312 flags = CIFS_ASYNC_OP | CIFS_OBREAK_OP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002313 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00002314 } else if (waitFlag) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002315 flags = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002316 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
2317 } else {
2318 pSMB->Timeout = 0;
2319 }
2320
2321 pSMB->NumberOfLocks = cpu_to_le16(numLock);
2322 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
2323 pSMB->LockType = lockType;
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002324 pSMB->OplockLevel = oplock_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002325 pSMB->AndXCommand = 0xFF; /* none */
2326 pSMB->Fid = smb_file_id; /* netfid stays le */
2327
Steve French790fe572007-07-07 19:25:05 +00002328 if ((numLock != 0) || (numUnlock != 0)) {
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002329 pSMB->Locks[0].Pid = cpu_to_le16(netpid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002330 /* BB where to store pid high? */
2331 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
2332 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
2333 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
2334 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
2335 count = sizeof(LOCKING_ANDX_RANGE);
2336 } else {
2337 /* oplock break */
2338 count = 0;
2339 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002340 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002341 pSMB->ByteCount = cpu_to_le16(count);
2342
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002343 if (waitFlag) {
2344 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002345 (struct smb_hdr *) pSMB, &bytes_returned);
Steve French133672e2007-11-13 22:41:37 +00002346 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002347 } else {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002348 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, flags);
Steve French133672e2007-11-13 22:41:37 +00002349 /* SMB buffer freed by function above */
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002350 }
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002351 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002352 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002353 cFYI(1, "Send error in Lock = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002354
Steve French50c2f752007-07-13 00:33:32 +00002355 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002356 since file handle passed in no longer valid */
2357 return rc;
2358}
2359
2360int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002361CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002362 const __u16 smb_file_id, const __u32 netpid,
2363 const loff_t start_offset, const __u64 len,
2364 struct file_lock *pLockData, const __u16 lock_type,
2365 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00002366{
2367 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2368 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00002369 struct cifs_posix_lock *parm_data;
2370 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00002371 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00002372 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00002373 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00002374 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00002375 struct kvec iov[1];
Steve French08547b02006-02-28 22:39:25 +00002376
Joe Perchesb6b38f72010-04-21 03:50:45 +00002377 cFYI(1, "Posix Lock");
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002378
Steve French08547b02006-02-28 22:39:25 +00002379 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
2380
2381 if (rc)
2382 return rc;
2383
2384 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
2385
Steve French50c2f752007-07-13 00:33:32 +00002386 params = 6;
Steve French08547b02006-02-28 22:39:25 +00002387 pSMB->MaxSetupCount = 0;
2388 pSMB->Reserved = 0;
2389 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00002390 pSMB->Reserved2 = 0;
2391 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2392 offset = param_offset + params;
2393
Steve French08547b02006-02-28 22:39:25 +00002394 count = sizeof(struct cifs_posix_lock);
2395 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002396 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00002397 pSMB->SetupCount = 1;
2398 pSMB->Reserved3 = 0;
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002399 if (pLockData)
Steve French08547b02006-02-28 22:39:25 +00002400 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2401 else
2402 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2403 byte_count = 3 /* pad */ + params + count;
2404 pSMB->DataCount = cpu_to_le16(count);
2405 pSMB->ParameterCount = cpu_to_le16(params);
2406 pSMB->TotalDataCount = pSMB->DataCount;
2407 pSMB->TotalParameterCount = pSMB->ParameterCount;
2408 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00002409 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00002410 (((char *) &pSMB->hdr.Protocol) + offset);
2411
2412 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00002413 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00002414 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00002415 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00002416 pSMB->Timeout = cpu_to_le32(-1);
2417 } else
2418 pSMB->Timeout = 0;
2419
Pavel Shilovsky4f6bcec2011-10-22 15:33:30 +04002420 parm_data->pid = cpu_to_le32(netpid);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002421 parm_data->start = cpu_to_le64(start_offset);
Steve Frenchcec6815a2006-05-30 18:07:17 +00002422 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00002423
2424 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00002425 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00002426 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
2427 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002428 inc_rfc1001_len(pSMB, byte_count);
Steve French08547b02006-02-28 22:39:25 +00002429 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002430 if (waitFlag) {
2431 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2432 (struct smb_hdr *) pSMBr, &bytes_returned);
2433 } else {
Steve French133672e2007-11-13 22:41:37 +00002434 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002435 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French133672e2007-11-13 22:41:37 +00002436 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
2437 &resp_buf_type, timeout);
2438 pSMB = NULL; /* request buf already freed by SendReceive2. Do
2439 not try to free it twice below on exit */
2440 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002441 }
2442
Steve French08547b02006-02-28 22:39:25 +00002443 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002444 cFYI(1, "Send error in Posix Lock = %d", rc);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002445 } else if (pLockData) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002446 /* lock structure can be returned on get */
2447 __u16 data_offset;
2448 __u16 data_count;
2449 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00002450
Jeff Layton820a8032011-05-04 08:05:26 -04002451 if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002452 rc = -EIO; /* bad smb */
2453 goto plk_err_exit;
2454 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002455 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2456 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00002457 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002458 rc = -EIO;
2459 goto plk_err_exit;
2460 }
2461 parm_data = (struct cifs_posix_lock *)
2462 ((char *)&pSMBr->hdr.Protocol + data_offset);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002463 if (parm_data->lock_type == __constant_cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002464 pLockData->fl_type = F_UNLCK;
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002465 else {
2466 if (parm_data->lock_type ==
2467 __constant_cpu_to_le16(CIFS_RDLCK))
2468 pLockData->fl_type = F_RDLCK;
2469 else if (parm_data->lock_type ==
2470 __constant_cpu_to_le16(CIFS_WRLCK))
2471 pLockData->fl_type = F_WRLCK;
2472
Steve French5443d132011-03-13 05:08:25 +00002473 pLockData->fl_start = le64_to_cpu(parm_data->start);
2474 pLockData->fl_end = pLockData->fl_start +
2475 le64_to_cpu(parm_data->length) - 1;
2476 pLockData->fl_pid = le32_to_cpu(parm_data->pid);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002477 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002478 }
Steve French50c2f752007-07-13 00:33:32 +00002479
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002480plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00002481 if (pSMB)
2482 cifs_small_buf_release(pSMB);
2483
Steve French133672e2007-11-13 22:41:37 +00002484 if (resp_buf_type == CIFS_SMALL_BUFFER)
2485 cifs_small_buf_release(iov[0].iov_base);
2486 else if (resp_buf_type == CIFS_LARGE_BUFFER)
2487 cifs_buf_release(iov[0].iov_base);
2488
Steve French08547b02006-02-28 22:39:25 +00002489 /* Note: On -EAGAIN error only caller can retry on handle based calls
2490 since file handle passed in no longer valid */
2491
2492 return rc;
2493}
2494
2495
2496int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002497CIFSSMBClose(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002498{
2499 int rc = 0;
2500 CLOSE_REQ *pSMB = NULL;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002501 cFYI(1, "In CIFSSMBClose");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002502
2503/* do not retry on dead session on close */
2504 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00002505 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002506 return 0;
2507 if (rc)
2508 return rc;
2509
Linus Torvalds1da177e2005-04-16 15:20:36 -07002510 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00002511 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002512 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002513 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002514 cifs_stats_inc(&tcon->stats.cifs_stats.num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00002516 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002517 /* EINTR is expected when user ctl-c to kill app */
Joe Perchesb6b38f72010-04-21 03:50:45 +00002518 cERROR(1, "Send error in Close = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002519 }
2520 }
2521
Linus Torvalds1da177e2005-04-16 15:20:36 -07002522 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00002523 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002524 rc = 0;
2525
2526 return rc;
2527}
2528
2529int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002530CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Steve Frenchb298f222009-02-21 21:17:43 +00002531{
2532 int rc = 0;
2533 FLUSH_REQ *pSMB = NULL;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002534 cFYI(1, "In CIFSSMBFlush");
Steve Frenchb298f222009-02-21 21:17:43 +00002535
2536 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
2537 if (rc)
2538 return rc;
2539
2540 pSMB->FileID = (__u16) smb_file_id;
2541 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002542 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002543 cifs_stats_inc(&tcon->stats.cifs_stats.num_flushes);
Steve Frenchb298f222009-02-21 21:17:43 +00002544 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002545 cERROR(1, "Send error in Flush = %d", rc);
Steve Frenchb298f222009-02-21 21:17:43 +00002546
2547 return rc;
2548}
2549
2550int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002551CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002552 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002553 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002554{
2555 int rc = 0;
2556 RENAME_REQ *pSMB = NULL;
2557 RENAME_RSP *pSMBr = NULL;
2558 int bytes_returned;
2559 int name_len, name_len2;
2560 __u16 count;
2561
Joe Perchesb6b38f72010-04-21 03:50:45 +00002562 cFYI(1, "In CIFSSMBRename");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002563renameRetry:
2564 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
2565 (void **) &pSMBr);
2566 if (rc)
2567 return rc;
2568
2569 pSMB->BufferFormat = 0x04;
2570 pSMB->SearchAttributes =
2571 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2572 ATTR_DIRECTORY);
2573
2574 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2575 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06002576 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, fromName,
2577 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002578 name_len++; /* trailing null */
2579 name_len *= 2;
2580 pSMB->OldFileName[name_len] = 0x04; /* pad */
2581 /* protocol requires ASCII signature byte on Unicode string */
2582 pSMB->OldFileName[name_len + 1] = 0x00;
2583 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002584 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2585 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002586 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2587 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002588 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002589 name_len = strnlen(fromName, PATH_MAX);
2590 name_len++; /* trailing null */
2591 strncpy(pSMB->OldFileName, fromName, name_len);
2592 name_len2 = strnlen(toName, PATH_MAX);
2593 name_len2++; /* trailing null */
2594 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2595 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2596 name_len2++; /* trailing null */
2597 name_len2++; /* signature byte */
2598 }
2599
2600 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002601 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002602 pSMB->ByteCount = cpu_to_le16(count);
2603
2604 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2605 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002606 cifs_stats_inc(&tcon->stats.cifs_stats.num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002607 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002608 cFYI(1, "Send error in rename = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002609
Linus Torvalds1da177e2005-04-16 15:20:36 -07002610 cifs_buf_release(pSMB);
2611
2612 if (rc == -EAGAIN)
2613 goto renameRetry;
2614
2615 return rc;
2616}
2617
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002618int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002619 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002620 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002621{
2622 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2623 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002624 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002625 char *data_offset;
2626 char dummy_string[30];
2627 int rc = 0;
2628 int bytes_returned = 0;
2629 int len_of_str;
2630 __u16 params, param_offset, offset, count, byte_count;
2631
Joe Perchesb6b38f72010-04-21 03:50:45 +00002632 cFYI(1, "Rename to File by handle");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002633 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2634 (void **) &pSMBr);
2635 if (rc)
2636 return rc;
2637
2638 params = 6;
2639 pSMB->MaxSetupCount = 0;
2640 pSMB->Reserved = 0;
2641 pSMB->Flags = 0;
2642 pSMB->Timeout = 0;
2643 pSMB->Reserved2 = 0;
2644 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2645 offset = param_offset + params;
2646
2647 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2648 rename_info = (struct set_file_rename *) data_offset;
2649 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002650 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651 pSMB->SetupCount = 1;
2652 pSMB->Reserved3 = 0;
2653 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2654 byte_count = 3 /* pad */ + params;
2655 pSMB->ParameterCount = cpu_to_le16(params);
2656 pSMB->TotalParameterCount = pSMB->ParameterCount;
2657 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2658 pSMB->DataOffset = cpu_to_le16(offset);
2659 /* construct random name ".cifs_tmp<inodenum><mid>" */
2660 rename_info->overwrite = cpu_to_le32(1);
2661 rename_info->root_fid = 0;
2662 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002663 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002664 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
Steve Frenchacbbb762012-01-18 22:32:33 -06002665 len_of_str =
2666 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002667 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002668 } else {
Steve Frenchacbbb762012-01-18 22:32:33 -06002669 len_of_str =
2670 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002671 target_name, PATH_MAX, nls_codepage,
2672 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002673 }
2674 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002675 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002676 byte_count += count;
2677 pSMB->DataCount = cpu_to_le16(count);
2678 pSMB->TotalDataCount = pSMB->DataCount;
2679 pSMB->Fid = netfid;
2680 pSMB->InformationLevel =
2681 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2682 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002683 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002684 pSMB->ByteCount = cpu_to_le16(byte_count);
2685 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002686 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002687 cifs_stats_inc(&pTcon->stats.cifs_stats.num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002688 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002689 cFYI(1, "Send error in Rename (by file handle) = %d", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07002690
Linus Torvalds1da177e2005-04-16 15:20:36 -07002691 cifs_buf_release(pSMB);
2692
2693 /* Note: On -EAGAIN error only caller can retry on handle based calls
2694 since file handle passed in no longer valid */
2695
2696 return rc;
2697}
2698
2699int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002700CIFSSMBCopy(const unsigned int xid, struct cifs_tcon *tcon,
2701 const char *fromName, const __u16 target_tid, const char *toName,
2702 const int flags, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002703{
2704 int rc = 0;
2705 COPY_REQ *pSMB = NULL;
2706 COPY_RSP *pSMBr = NULL;
2707 int bytes_returned;
2708 int name_len, name_len2;
2709 __u16 count;
2710
Joe Perchesb6b38f72010-04-21 03:50:45 +00002711 cFYI(1, "In CIFSSMBCopy");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002712copyRetry:
2713 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2714 (void **) &pSMBr);
2715 if (rc)
2716 return rc;
2717
2718 pSMB->BufferFormat = 0x04;
2719 pSMB->Tid2 = target_tid;
2720
2721 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2722
2723 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002724 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2725 fromName, PATH_MAX, nls_codepage,
2726 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002727 name_len++; /* trailing null */
2728 name_len *= 2;
2729 pSMB->OldFileName[name_len] = 0x04; /* pad */
2730 /* protocol requires ASCII signature byte on Unicode string */
2731 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002732 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002733 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2734 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2736 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002737 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002738 name_len = strnlen(fromName, PATH_MAX);
2739 name_len++; /* trailing null */
2740 strncpy(pSMB->OldFileName, fromName, name_len);
2741 name_len2 = strnlen(toName, PATH_MAX);
2742 name_len2++; /* trailing null */
2743 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2744 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2745 name_len2++; /* trailing null */
2746 name_len2++; /* signature byte */
2747 }
2748
2749 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002750 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002751 pSMB->ByteCount = cpu_to_le16(count);
2752
2753 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2754 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2755 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002756 cFYI(1, "Send error in copy = %d with %d files copied",
2757 rc, le16_to_cpu(pSMBr->CopyCount));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002758 }
Steve French0d817bc2008-05-22 02:02:03 +00002759 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002760
2761 if (rc == -EAGAIN)
2762 goto copyRetry;
2763
2764 return rc;
2765}
2766
2767int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002768CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002769 const char *fromName, const char *toName,
2770 const struct nls_table *nls_codepage)
2771{
2772 TRANSACTION2_SPI_REQ *pSMB = NULL;
2773 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2774 char *data_offset;
2775 int name_len;
2776 int name_len_target;
2777 int rc = 0;
2778 int bytes_returned = 0;
2779 __u16 params, param_offset, offset, byte_count;
2780
Joe Perchesb6b38f72010-04-21 03:50:45 +00002781 cFYI(1, "In Symlink Unix style");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002782createSymLinkRetry:
2783 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2784 (void **) &pSMBr);
2785 if (rc)
2786 return rc;
2787
2788 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2789 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06002790 cifs_strtoUTF16((__le16 *) pSMB->FileName, fromName,
2791 /* find define for this maxpathcomponent */
2792 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002793 name_len++; /* trailing null */
2794 name_len *= 2;
2795
Steve French50c2f752007-07-13 00:33:32 +00002796 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002797 name_len = strnlen(fromName, PATH_MAX);
2798 name_len++; /* trailing null */
2799 strncpy(pSMB->FileName, fromName, name_len);
2800 }
2801 params = 6 + name_len;
2802 pSMB->MaxSetupCount = 0;
2803 pSMB->Reserved = 0;
2804 pSMB->Flags = 0;
2805 pSMB->Timeout = 0;
2806 pSMB->Reserved2 = 0;
2807 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002808 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002809 offset = param_offset + params;
2810
2811 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2812 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2813 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06002814 cifs_strtoUTF16((__le16 *) data_offset, toName, PATH_MAX
2815 /* find define for this maxpathcomponent */
2816 , nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002817 name_len_target++; /* trailing null */
2818 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002819 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002820 name_len_target = strnlen(toName, PATH_MAX);
2821 name_len_target++; /* trailing null */
2822 strncpy(data_offset, toName, name_len_target);
2823 }
2824
2825 pSMB->MaxParameterCount = cpu_to_le16(2);
2826 /* BB find exact max on data count below from sess */
2827 pSMB->MaxDataCount = cpu_to_le16(1000);
2828 pSMB->SetupCount = 1;
2829 pSMB->Reserved3 = 0;
2830 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2831 byte_count = 3 /* pad */ + params + name_len_target;
2832 pSMB->DataCount = cpu_to_le16(name_len_target);
2833 pSMB->ParameterCount = cpu_to_le16(params);
2834 pSMB->TotalDataCount = pSMB->DataCount;
2835 pSMB->TotalParameterCount = pSMB->ParameterCount;
2836 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2837 pSMB->DataOffset = cpu_to_le16(offset);
2838 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2839 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002840 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002841 pSMB->ByteCount = cpu_to_le16(byte_count);
2842 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2843 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002844 cifs_stats_inc(&tcon->stats.cifs_stats.num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002845 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002846 cFYI(1, "Send error in SetPathInfo create symlink = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002847
Steve French0d817bc2008-05-22 02:02:03 +00002848 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002849
2850 if (rc == -EAGAIN)
2851 goto createSymLinkRetry;
2852
2853 return rc;
2854}
2855
2856int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002857CIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002858 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002859 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002860{
2861 TRANSACTION2_SPI_REQ *pSMB = NULL;
2862 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2863 char *data_offset;
2864 int name_len;
2865 int name_len_target;
2866 int rc = 0;
2867 int bytes_returned = 0;
2868 __u16 params, param_offset, offset, byte_count;
2869
Joe Perchesb6b38f72010-04-21 03:50:45 +00002870 cFYI(1, "In Create Hard link Unix style");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002871createHardLinkRetry:
2872 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2873 (void **) &pSMBr);
2874 if (rc)
2875 return rc;
2876
2877 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002878 name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, toName,
2879 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002880 name_len++; /* trailing null */
2881 name_len *= 2;
2882
Steve French50c2f752007-07-13 00:33:32 +00002883 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002884 name_len = strnlen(toName, PATH_MAX);
2885 name_len++; /* trailing null */
2886 strncpy(pSMB->FileName, toName, name_len);
2887 }
2888 params = 6 + name_len;
2889 pSMB->MaxSetupCount = 0;
2890 pSMB->Reserved = 0;
2891 pSMB->Flags = 0;
2892 pSMB->Timeout = 0;
2893 pSMB->Reserved2 = 0;
2894 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002895 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002896 offset = param_offset + params;
2897
2898 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2899 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2900 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06002901 cifsConvertToUTF16((__le16 *) data_offset, fromName,
2902 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002903 name_len_target++; /* trailing null */
2904 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002905 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002906 name_len_target = strnlen(fromName, PATH_MAX);
2907 name_len_target++; /* trailing null */
2908 strncpy(data_offset, fromName, name_len_target);
2909 }
2910
2911 pSMB->MaxParameterCount = cpu_to_le16(2);
2912 /* BB find exact max on data count below from sess*/
2913 pSMB->MaxDataCount = cpu_to_le16(1000);
2914 pSMB->SetupCount = 1;
2915 pSMB->Reserved3 = 0;
2916 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2917 byte_count = 3 /* pad */ + params + name_len_target;
2918 pSMB->ParameterCount = cpu_to_le16(params);
2919 pSMB->TotalParameterCount = pSMB->ParameterCount;
2920 pSMB->DataCount = cpu_to_le16(name_len_target);
2921 pSMB->TotalDataCount = pSMB->DataCount;
2922 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2923 pSMB->DataOffset = cpu_to_le16(offset);
2924 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2925 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002926 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002927 pSMB->ByteCount = cpu_to_le16(byte_count);
2928 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2929 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002930 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002931 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002932 cFYI(1, "Send error in SetPathInfo (hard link) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002933
2934 cifs_buf_release(pSMB);
2935 if (rc == -EAGAIN)
2936 goto createHardLinkRetry;
2937
2938 return rc;
2939}
2940
2941int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002942CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002943 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002944 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002945{
2946 int rc = 0;
2947 NT_RENAME_REQ *pSMB = NULL;
2948 RENAME_RSP *pSMBr = NULL;
2949 int bytes_returned;
2950 int name_len, name_len2;
2951 __u16 count;
2952
Joe Perchesb6b38f72010-04-21 03:50:45 +00002953 cFYI(1, "In CIFSCreateHardLink");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002954winCreateHardLinkRetry:
2955
2956 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2957 (void **) &pSMBr);
2958 if (rc)
2959 return rc;
2960
2961 pSMB->SearchAttributes =
2962 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2963 ATTR_DIRECTORY);
2964 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2965 pSMB->ClusterCount = 0;
2966
2967 pSMB->BufferFormat = 0x04;
2968
2969 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2970 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06002971 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, fromName,
2972 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002973 name_len++; /* trailing null */
2974 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05002975
2976 /* protocol specifies ASCII buffer format (0x04) for unicode */
2977 pSMB->OldFileName[name_len] = 0x04;
2978 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002979 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002980 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2981 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002982 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2983 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002984 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002985 name_len = strnlen(fromName, PATH_MAX);
2986 name_len++; /* trailing null */
2987 strncpy(pSMB->OldFileName, fromName, name_len);
2988 name_len2 = strnlen(toName, PATH_MAX);
2989 name_len2++; /* trailing null */
2990 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2991 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2992 name_len2++; /* trailing null */
2993 name_len2++; /* signature byte */
2994 }
2995
2996 count = 1 /* string type byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002997 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002998 pSMB->ByteCount = cpu_to_le16(count);
2999
3000 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3001 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003002 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00003003 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003004 cFYI(1, "Send error in hard link (NT rename) = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00003005
Linus Torvalds1da177e2005-04-16 15:20:36 -07003006 cifs_buf_release(pSMB);
3007 if (rc == -EAGAIN)
3008 goto winCreateHardLinkRetry;
3009
3010 return rc;
3011}
3012
3013int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003014CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04003015 const unsigned char *searchName, char **symlinkinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003016 const struct nls_table *nls_codepage)
3017{
3018/* SMB_QUERY_FILE_UNIX_LINK */
3019 TRANSACTION2_QPI_REQ *pSMB = NULL;
3020 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3021 int rc = 0;
3022 int bytes_returned;
3023 int name_len;
3024 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04003025 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003026
Joe Perchesb6b38f72010-04-21 03:50:45 +00003027 cFYI(1, "In QPathSymLinkInfo (Unix) for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003028
3029querySymLinkRetry:
3030 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3031 (void **) &pSMBr);
3032 if (rc)
3033 return rc;
3034
3035 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3036 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003037 cifs_strtoUTF16((__le16 *) pSMB->FileName, searchName,
3038 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003039 name_len++; /* trailing null */
3040 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003041 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003042 name_len = strnlen(searchName, PATH_MAX);
3043 name_len++; /* trailing null */
3044 strncpy(pSMB->FileName, searchName, name_len);
3045 }
3046
3047 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3048 pSMB->TotalDataCount = 0;
3049 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04003050 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003051 pSMB->MaxSetupCount = 0;
3052 pSMB->Reserved = 0;
3053 pSMB->Flags = 0;
3054 pSMB->Timeout = 0;
3055 pSMB->Reserved2 = 0;
3056 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003057 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003058 pSMB->DataCount = 0;
3059 pSMB->DataOffset = 0;
3060 pSMB->SetupCount = 1;
3061 pSMB->Reserved3 = 0;
3062 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3063 byte_count = params + 1 /* pad */ ;
3064 pSMB->TotalParameterCount = cpu_to_le16(params);
3065 pSMB->ParameterCount = pSMB->TotalParameterCount;
3066 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
3067 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003068 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003069 pSMB->ByteCount = cpu_to_le16(byte_count);
3070
3071 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3072 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3073 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003074 cFYI(1, "Send error in QuerySymLinkInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003075 } else {
3076 /* decode response */
3077
3078 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003079 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003080 if (rc || get_bcc(&pSMBr->hdr) < 2)
Jeff Layton460b9692009-04-30 07:17:56 -04003081 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003082 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00003083 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04003084 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003085
Jeff Layton460b9692009-04-30 07:17:56 -04003086 data_start = ((char *) &pSMBr->hdr.Protocol) +
3087 le16_to_cpu(pSMBr->t2.DataOffset);
3088
Steve French0e0d2cf2009-05-01 05:27:32 +00003089 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3090 is_unicode = true;
3091 else
3092 is_unicode = false;
3093
Steve French737b7582005-04-28 22:41:06 -07003094 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchacbbb762012-01-18 22:32:33 -06003095 *symlinkinfo = cifs_strndup_from_utf16(data_start,
3096 count, is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04003097 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04003098 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003099 }
3100 }
3101 cifs_buf_release(pSMB);
3102 if (rc == -EAGAIN)
3103 goto querySymLinkRetry;
3104 return rc;
3105}
3106
Steve Frenchc52a9552011-02-24 06:16:22 +00003107#ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL
3108/*
3109 * Recent Windows versions now create symlinks more frequently
3110 * and they use the "reparse point" mechanism below. We can of course
3111 * do symlinks nicely to Samba and other servers which support the
3112 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
3113 * "MF" symlinks optionally, but for recent Windows we really need to
3114 * reenable the code below and fix the cifs_symlink callers to handle this.
3115 * In the interim this code has been moved to its own config option so
3116 * it is not compiled in by default until callers fixed up and more tested.
3117 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003118int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003119CIFSSMBQueryReparseLinkInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003120 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00003121 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003122 const struct nls_table *nls_codepage)
3123{
3124 int rc = 0;
3125 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00003126 struct smb_com_transaction_ioctl_req *pSMB;
3127 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003128
Joe Perchesb6b38f72010-04-21 03:50:45 +00003129 cFYI(1, "In Windows reparse style QueryLink for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003130 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3131 (void **) &pSMBr);
3132 if (rc)
3133 return rc;
3134
3135 pSMB->TotalParameterCount = 0 ;
3136 pSMB->TotalDataCount = 0;
3137 pSMB->MaxParameterCount = cpu_to_le32(2);
3138 /* BB find exact data count max from sess structure BB */
Jeff Laytonc974bef2011-10-11 06:41:32 -04003139 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003140 pSMB->MaxSetupCount = 4;
3141 pSMB->Reserved = 0;
3142 pSMB->ParameterOffset = 0;
3143 pSMB->DataCount = 0;
3144 pSMB->DataOffset = 0;
3145 pSMB->SetupCount = 4;
3146 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
3147 pSMB->ParameterCount = pSMB->TotalParameterCount;
3148 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
3149 pSMB->IsFsctl = 1; /* FSCTL */
3150 pSMB->IsRootFlag = 0;
3151 pSMB->Fid = fid; /* file handle always le */
3152 pSMB->ByteCount = 0;
3153
3154 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3155 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3156 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003157 cFYI(1, "Send error in QueryReparseLinkInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003158 } else { /* decode response */
3159 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
3160 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
Jeff Layton820a8032011-05-04 08:05:26 -04003161 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
3162 /* BB also check enough total bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003163 rc = -EIO; /* bad smb */
Steve Frenchafe48c32009-05-02 05:25:46 +00003164 goto qreparse_out;
3165 }
3166 if (data_count && (data_count < 2048)) {
3167 char *end_of_smb = 2 /* sizeof byte count */ +
Jeff Layton820a8032011-05-04 08:05:26 -04003168 get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003169
Steve Frenchafe48c32009-05-02 05:25:46 +00003170 struct reparse_data *reparse_buf =
Steve French50c2f752007-07-13 00:33:32 +00003171 (struct reparse_data *)
3172 ((char *)&pSMBr->hdr.Protocol
3173 + data_offset);
Steve Frenchafe48c32009-05-02 05:25:46 +00003174 if ((char *)reparse_buf >= end_of_smb) {
3175 rc = -EIO;
3176 goto qreparse_out;
3177 }
3178 if ((reparse_buf->LinkNamesBuf +
3179 reparse_buf->TargetNameOffset +
3180 reparse_buf->TargetNameLen) > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003181 cFYI(1, "reparse buf beyond SMB");
Steve Frenchafe48c32009-05-02 05:25:46 +00003182 rc = -EIO;
3183 goto qreparse_out;
3184 }
Steve French50c2f752007-07-13 00:33:32 +00003185
Steve Frenchafe48c32009-05-02 05:25:46 +00003186 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3187 cifs_from_ucs2(symlinkinfo, (__le16 *)
Steve French50c2f752007-07-13 00:33:32 +00003188 (reparse_buf->LinkNamesBuf +
3189 reparse_buf->TargetNameOffset),
Steve Frenchafe48c32009-05-02 05:25:46 +00003190 buflen,
3191 reparse_buf->TargetNameLen,
3192 nls_codepage, 0);
3193 } else { /* ASCII names */
3194 strncpy(symlinkinfo,
3195 reparse_buf->LinkNamesBuf +
3196 reparse_buf->TargetNameOffset,
3197 min_t(const int, buflen,
3198 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003199 }
Steve Frenchafe48c32009-05-02 05:25:46 +00003200 } else {
3201 rc = -EIO;
Joe Perchesb6b38f72010-04-21 03:50:45 +00003202 cFYI(1, "Invalid return data count on "
3203 "get reparse info ioctl");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003204 }
Steve Frenchafe48c32009-05-02 05:25:46 +00003205 symlinkinfo[buflen] = 0; /* just in case so the caller
3206 does not go off the end of the buffer */
Joe Perchesb6b38f72010-04-21 03:50:45 +00003207 cFYI(1, "readlink result - %s", symlinkinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003208 }
Steve French989c7e52009-05-02 05:32:20 +00003209
Linus Torvalds1da177e2005-04-16 15:20:36 -07003210qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07003211 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003212
3213 /* Note: On -EAGAIN error only caller can retry on handle based calls
3214 since file handle passed in no longer valid */
3215
3216 return rc;
3217}
Steve Frenchc52a9552011-02-24 06:16:22 +00003218#endif /* CIFS_SYMLINK_EXPERIMENTAL */ /* BB temporarily unused */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003219
3220#ifdef CONFIG_CIFS_POSIX
3221
3222/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00003223static void cifs_convert_ace(posix_acl_xattr_entry *ace,
3224 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003225{
3226 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08003227 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
3228 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
3229 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesb6b38f72010-04-21 03:50:45 +00003230 /* cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003231
3232 return;
3233}
3234
3235/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00003236static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
3237 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003238{
3239 int size = 0;
3240 int i;
3241 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00003242 struct cifs_posix_ace *pACE;
3243 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
3244 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003245
3246 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
3247 return -EOPNOTSUPP;
3248
Steve French790fe572007-07-07 19:25:05 +00003249 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003250 count = le16_to_cpu(cifs_acl->access_entry_count);
3251 pACE = &cifs_acl->ace_array[0];
3252 size = sizeof(struct cifs_posix_acl);
3253 size += sizeof(struct cifs_posix_ace) * count;
3254 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003255 if (size_of_data_area < size) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003256 cFYI(1, "bad CIFS POSIX ACL size %d vs. %d",
3257 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003258 return -EINVAL;
3259 }
Steve French790fe572007-07-07 19:25:05 +00003260 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003261 count = le16_to_cpu(cifs_acl->access_entry_count);
3262 size = sizeof(struct cifs_posix_acl);
3263 size += sizeof(struct cifs_posix_ace) * count;
3264/* skip past access ACEs to get to default ACEs */
3265 pACE = &cifs_acl->ace_array[count];
3266 count = le16_to_cpu(cifs_acl->default_entry_count);
3267 size += sizeof(struct cifs_posix_ace) * count;
3268 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003269 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003270 return -EINVAL;
3271 } else {
3272 /* illegal type */
3273 return -EINVAL;
3274 }
3275
3276 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00003277 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00003278 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00003279 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003280 return -ERANGE;
3281 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08003282 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00003283 for (i = 0; i < count ; i++) {
3284 cifs_convert_ace(&local_acl->a_entries[i], pACE);
3285 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003286 }
3287 }
3288 return size;
3289}
3290
Steve French50c2f752007-07-13 00:33:32 +00003291static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
3292 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003293{
3294 __u16 rc = 0; /* 0 = ACL converted ok */
3295
Steve Frenchff7feac2005-11-15 16:45:16 -08003296 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
3297 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003298 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00003299 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003300 /* Probably no need to le convert -1 on any arch but can not hurt */
3301 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00003302 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08003303 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesb6b38f72010-04-21 03:50:45 +00003304 /*cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id);*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003305 return rc;
3306}
3307
3308/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00003309static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
3310 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003311{
3312 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00003313 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
3314 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003315 int count;
3316 int i;
3317
Steve French790fe572007-07-07 19:25:05 +00003318 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003319 return 0;
3320
3321 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesb6b38f72010-04-21 03:50:45 +00003322 cFYI(1, "setting acl with %d entries from buf of length %d and "
Steve French63135e02007-07-17 17:34:02 +00003323 "version of %d",
Joe Perchesb6b38f72010-04-21 03:50:45 +00003324 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00003325 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003326 cFYI(1, "unknown POSIX ACL version %d",
3327 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003328 return 0;
3329 }
3330 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00003331 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08003332 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00003333 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08003334 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003335 else {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003336 cFYI(1, "unknown ACL type %d", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003337 return 0;
3338 }
Steve French50c2f752007-07-13 00:33:32 +00003339 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003340 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
3341 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00003342 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003343 /* ACE not converted */
3344 break;
3345 }
3346 }
Steve French790fe572007-07-07 19:25:05 +00003347 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003348 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
3349 rc += sizeof(struct cifs_posix_acl);
3350 /* BB add check to make sure ACL does not overflow SMB */
3351 }
3352 return rc;
3353}
3354
3355int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003356CIFSSMBGetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003357 const unsigned char *searchName,
3358 char *acl_inf, const int buflen, const int acl_type,
3359 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003360{
3361/* SMB_QUERY_POSIX_ACL */
3362 TRANSACTION2_QPI_REQ *pSMB = NULL;
3363 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3364 int rc = 0;
3365 int bytes_returned;
3366 int name_len;
3367 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00003368
Joe Perchesb6b38f72010-04-21 03:50:45 +00003369 cFYI(1, "In GetPosixACL (Unix) for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003370
3371queryAclRetry:
3372 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3373 (void **) &pSMBr);
3374 if (rc)
3375 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003376
Linus Torvalds1da177e2005-04-16 15:20:36 -07003377 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3378 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003379 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3380 searchName, PATH_MAX, nls_codepage,
3381 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003382 name_len++; /* trailing null */
3383 name_len *= 2;
3384 pSMB->FileName[name_len] = 0;
3385 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00003386 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003387 name_len = strnlen(searchName, PATH_MAX);
3388 name_len++; /* trailing null */
3389 strncpy(pSMB->FileName, searchName, name_len);
3390 }
3391
3392 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3393 pSMB->TotalDataCount = 0;
3394 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00003395 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003396 pSMB->MaxDataCount = cpu_to_le16(4000);
3397 pSMB->MaxSetupCount = 0;
3398 pSMB->Reserved = 0;
3399 pSMB->Flags = 0;
3400 pSMB->Timeout = 0;
3401 pSMB->Reserved2 = 0;
3402 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003403 offsetof(struct smb_com_transaction2_qpi_req,
3404 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003405 pSMB->DataCount = 0;
3406 pSMB->DataOffset = 0;
3407 pSMB->SetupCount = 1;
3408 pSMB->Reserved3 = 0;
3409 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3410 byte_count = params + 1 /* pad */ ;
3411 pSMB->TotalParameterCount = cpu_to_le16(params);
3412 pSMB->ParameterCount = pSMB->TotalParameterCount;
3413 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
3414 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003415 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003416 pSMB->ByteCount = cpu_to_le16(byte_count);
3417
3418 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3419 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003420 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003421 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003422 cFYI(1, "Send error in Query POSIX ACL = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003423 } else {
3424 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00003425
Linus Torvalds1da177e2005-04-16 15:20:36 -07003426 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003427 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003428 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003429 rc = -EIO; /* bad smb */
3430 else {
3431 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3432 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3433 rc = cifs_copy_posix_acl(acl_inf,
3434 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00003435 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003436 }
3437 }
3438 cifs_buf_release(pSMB);
3439 if (rc == -EAGAIN)
3440 goto queryAclRetry;
3441 return rc;
3442}
3443
3444int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003445CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003446 const unsigned char *fileName,
3447 const char *local_acl, const int buflen,
3448 const int acl_type,
3449 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003450{
3451 struct smb_com_transaction2_spi_req *pSMB = NULL;
3452 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3453 char *parm_data;
3454 int name_len;
3455 int rc = 0;
3456 int bytes_returned = 0;
3457 __u16 params, byte_count, data_count, param_offset, offset;
3458
Joe Perchesb6b38f72010-04-21 03:50:45 +00003459 cFYI(1, "In SetPosixACL (Unix) for path %s", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003460setAclRetry:
3461 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003462 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003463 if (rc)
3464 return rc;
3465 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3466 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003467 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
3468 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003469 name_len++; /* trailing null */
3470 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003471 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003472 name_len = strnlen(fileName, PATH_MAX);
3473 name_len++; /* trailing null */
3474 strncpy(pSMB->FileName, fileName, name_len);
3475 }
3476 params = 6 + name_len;
3477 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003478 /* BB find max SMB size from sess */
3479 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003480 pSMB->MaxSetupCount = 0;
3481 pSMB->Reserved = 0;
3482 pSMB->Flags = 0;
3483 pSMB->Timeout = 0;
3484 pSMB->Reserved2 = 0;
3485 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003486 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003487 offset = param_offset + params;
3488 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
3489 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3490
3491 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00003492 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003493
Steve French790fe572007-07-07 19:25:05 +00003494 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003495 rc = -EOPNOTSUPP;
3496 goto setACLerrorExit;
3497 }
3498 pSMB->DataOffset = cpu_to_le16(offset);
3499 pSMB->SetupCount = 1;
3500 pSMB->Reserved3 = 0;
3501 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3502 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
3503 byte_count = 3 /* pad */ + params + data_count;
3504 pSMB->DataCount = cpu_to_le16(data_count);
3505 pSMB->TotalDataCount = pSMB->DataCount;
3506 pSMB->ParameterCount = cpu_to_le16(params);
3507 pSMB->TotalParameterCount = pSMB->ParameterCount;
3508 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003509 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003510 pSMB->ByteCount = cpu_to_le16(byte_count);
3511 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003512 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003513 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003514 cFYI(1, "Set POSIX ACL returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003515
3516setACLerrorExit:
3517 cifs_buf_release(pSMB);
3518 if (rc == -EAGAIN)
3519 goto setAclRetry;
3520 return rc;
3521}
3522
Steve Frenchf654bac2005-04-28 22:41:04 -07003523/* BB fix tabs in this function FIXME BB */
3524int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003525CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00003526 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07003527{
Steve French50c2f752007-07-13 00:33:32 +00003528 int rc = 0;
3529 struct smb_t2_qfi_req *pSMB = NULL;
3530 struct smb_t2_qfi_rsp *pSMBr = NULL;
3531 int bytes_returned;
3532 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07003533
Joe Perchesb6b38f72010-04-21 03:50:45 +00003534 cFYI(1, "In GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00003535 if (tcon == NULL)
3536 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07003537
3538GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003539 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3540 (void **) &pSMBr);
3541 if (rc)
3542 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003543
Steve Frenchad7a2922008-02-07 23:25:02 +00003544 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003545 pSMB->t2.TotalDataCount = 0;
3546 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3547 /* BB find exact max data count below from sess structure BB */
3548 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3549 pSMB->t2.MaxSetupCount = 0;
3550 pSMB->t2.Reserved = 0;
3551 pSMB->t2.Flags = 0;
3552 pSMB->t2.Timeout = 0;
3553 pSMB->t2.Reserved2 = 0;
3554 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3555 Fid) - 4);
3556 pSMB->t2.DataCount = 0;
3557 pSMB->t2.DataOffset = 0;
3558 pSMB->t2.SetupCount = 1;
3559 pSMB->t2.Reserved3 = 0;
3560 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3561 byte_count = params + 1 /* pad */ ;
3562 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3563 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3564 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3565 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003566 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003567 inc_rfc1001_len(pSMB, byte_count);
Steve French790fe572007-07-07 19:25:05 +00003568 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003569
Steve French790fe572007-07-07 19:25:05 +00003570 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3571 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3572 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003573 cFYI(1, "error %d in GetExtAttr", rc);
Steve French790fe572007-07-07 19:25:05 +00003574 } else {
3575 /* decode response */
3576 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003577 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003578 if (rc || get_bcc(&pSMBr->hdr) < 2)
Steve French790fe572007-07-07 19:25:05 +00003579 /* If rc should we check for EOPNOSUPP and
3580 disable the srvino flag? or in caller? */
3581 rc = -EIO; /* bad smb */
3582 else {
3583 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3584 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3585 struct file_chattr_info *pfinfo;
3586 /* BB Do we need a cast or hash here ? */
3587 if (count != 16) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003588 cFYI(1, "Illegal size ret in GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00003589 rc = -EIO;
3590 goto GetExtAttrOut;
3591 }
3592 pfinfo = (struct file_chattr_info *)
3593 (data_offset + (char *) &pSMBr->hdr.Protocol);
3594 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003595 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003596 }
3597 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003598GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003599 cifs_buf_release(pSMB);
3600 if (rc == -EAGAIN)
3601 goto GetExtAttrRetry;
3602 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003603}
3604
Steve Frenchf654bac2005-04-28 22:41:04 -07003605#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003606
Jeff Layton79df1ba2010-12-06 12:52:08 -05003607#ifdef CONFIG_CIFS_ACL
3608/*
3609 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3610 * all NT TRANSACTS that we init here have total parm and data under about 400
3611 * bytes (to fit in small cifs buffer size), which is the case so far, it
3612 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3613 * returned setup area) and MaxParameterCount (returned parms size) must be set
3614 * by caller
3615 */
3616static int
3617smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French96daf2b2011-05-27 04:34:02 +00003618 const int parm_len, struct cifs_tcon *tcon,
Jeff Layton79df1ba2010-12-06 12:52:08 -05003619 void **ret_buf)
3620{
3621 int rc;
3622 __u32 temp_offset;
3623 struct smb_com_ntransact_req *pSMB;
3624
3625 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3626 (void **)&pSMB);
3627 if (rc)
3628 return rc;
3629 *ret_buf = (void *)pSMB;
3630 pSMB->Reserved = 0;
3631 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3632 pSMB->TotalDataCount = 0;
Jeff Laytonc974bef2011-10-11 06:41:32 -04003633 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003634 pSMB->ParameterCount = pSMB->TotalParameterCount;
3635 pSMB->DataCount = pSMB->TotalDataCount;
3636 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3637 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3638 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3639 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3640 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3641 pSMB->SubCommand = cpu_to_le16(sub_command);
3642 return 0;
3643}
3644
3645static int
3646validate_ntransact(char *buf, char **ppparm, char **ppdata,
3647 __u32 *pparmlen, __u32 *pdatalen)
3648{
3649 char *end_of_smb;
3650 __u32 data_count, data_offset, parm_count, parm_offset;
3651 struct smb_com_ntransact_rsp *pSMBr;
Jeff Layton820a8032011-05-04 08:05:26 -04003652 u16 bcc;
Jeff Layton79df1ba2010-12-06 12:52:08 -05003653
3654 *pdatalen = 0;
3655 *pparmlen = 0;
3656
3657 if (buf == NULL)
3658 return -EINVAL;
3659
3660 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3661
Jeff Layton820a8032011-05-04 08:05:26 -04003662 bcc = get_bcc(&pSMBr->hdr);
3663 end_of_smb = 2 /* sizeof byte count */ + bcc +
Jeff Layton79df1ba2010-12-06 12:52:08 -05003664 (char *)&pSMBr->ByteCount;
3665
3666 data_offset = le32_to_cpu(pSMBr->DataOffset);
3667 data_count = le32_to_cpu(pSMBr->DataCount);
3668 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3669 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3670
3671 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3672 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3673
3674 /* should we also check that parm and data areas do not overlap? */
3675 if (*ppparm > end_of_smb) {
3676 cFYI(1, "parms start after end of smb");
3677 return -EINVAL;
3678 } else if (parm_count + *ppparm > end_of_smb) {
3679 cFYI(1, "parm end after end of smb");
3680 return -EINVAL;
3681 } else if (*ppdata > end_of_smb) {
3682 cFYI(1, "data starts after end of smb");
3683 return -EINVAL;
3684 } else if (data_count + *ppdata > end_of_smb) {
3685 cFYI(1, "data %p + count %d (%p) past smb end %p start %p",
3686 *ppdata, data_count, (data_count + *ppdata),
3687 end_of_smb, pSMBr);
3688 return -EINVAL;
Jeff Layton820a8032011-05-04 08:05:26 -04003689 } else if (parm_count + data_count > bcc) {
Jeff Layton79df1ba2010-12-06 12:52:08 -05003690 cFYI(1, "parm count and data count larger than SMB");
3691 return -EINVAL;
3692 }
3693 *pdatalen = data_count;
3694 *pparmlen = parm_count;
3695 return 0;
3696}
3697
Steve French0a4b92c2006-01-12 15:44:21 -08003698/* Get Security Descriptor (by handle) from remote server for a file or dir */
3699int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003700CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003701 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003702{
3703 int rc = 0;
3704 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003705 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003706 struct kvec iov[1];
3707
Joe Perchesb6b38f72010-04-21 03:50:45 +00003708 cFYI(1, "GetCifsACL");
Steve French0a4b92c2006-01-12 15:44:21 -08003709
Steve French630f3f0c2007-10-25 21:17:17 +00003710 *pbuflen = 0;
3711 *acl_inf = NULL;
3712
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003713 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003714 8 /* parm len */, tcon, (void **) &pSMB);
3715 if (rc)
3716 return rc;
3717
3718 pSMB->MaxParameterCount = cpu_to_le32(4);
3719 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3720 pSMB->MaxSetupCount = 0;
3721 pSMB->Fid = fid; /* file handle always le */
3722 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3723 CIFS_ACL_DACL);
3724 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003725 inc_rfc1001_len(pSMB, 11);
Steve French0a4b92c2006-01-12 15:44:21 -08003726 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003727 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French0a4b92c2006-01-12 15:44:21 -08003728
Steve Frencha761ac52007-10-18 21:45:27 +00003729 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Jeff Layton77499812011-01-11 07:24:23 -05003730 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003731 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Steve French0a4b92c2006-01-12 15:44:21 -08003732 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003733 cFYI(1, "Send error in QuerySecDesc = %d", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08003734 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003735 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003736 __u32 parm_len;
3737 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003738 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003739 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003740
3741/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003742 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003743 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003744 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003745 goto qsec_out;
3746 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3747
Joe Perchesb6b38f72010-04-21 03:50:45 +00003748 cFYI(1, "smb %p parm %p data %p", pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08003749
3750 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3751 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003752 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003753 goto qsec_out;
3754 }
3755
3756/* BB check that data area is minimum length and as big as acl_len */
3757
Steve Frenchaf6f4612007-10-16 18:40:37 +00003758 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003759 if (acl_len != *pbuflen) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003760 cERROR(1, "acl length %d does not match %d",
3761 acl_len, *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003762 if (*pbuflen > acl_len)
3763 *pbuflen = acl_len;
3764 }
Steve French0a4b92c2006-01-12 15:44:21 -08003765
Steve French630f3f0c2007-10-25 21:17:17 +00003766 /* check if buffer is big enough for the acl
3767 header followed by the smallest SID */
3768 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3769 (*pbuflen >= 64 * 1024)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003770 cERROR(1, "bad acl length %d", *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003771 rc = -EINVAL;
3772 *pbuflen = 0;
3773 } else {
3774 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3775 if (*acl_inf == NULL) {
3776 *pbuflen = 0;
3777 rc = -ENOMEM;
3778 }
3779 memcpy(*acl_inf, pdata, *pbuflen);
3780 }
Steve French0a4b92c2006-01-12 15:44:21 -08003781 }
3782qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003783 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003784 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003785 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003786 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003787/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003788 return rc;
3789}
Steve French97837582007-12-31 07:47:21 +00003790
3791int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003792CIFSSMBSetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003793 struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
Steve French97837582007-12-31 07:47:21 +00003794{
3795 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3796 int rc = 0;
3797 int bytes_returned = 0;
3798 SET_SEC_DESC_REQ *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003799 void *pSMBr;
Steve French97837582007-12-31 07:47:21 +00003800
3801setCifsAclRetry:
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003802 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, &pSMBr);
Steve French97837582007-12-31 07:47:21 +00003803 if (rc)
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003804 return rc;
Steve French97837582007-12-31 07:47:21 +00003805
3806 pSMB->MaxSetupCount = 0;
3807 pSMB->Reserved = 0;
3808
3809 param_count = 8;
3810 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3811 data_count = acllen;
3812 data_offset = param_offset + param_count;
3813 byte_count = 3 /* pad */ + param_count;
3814
3815 pSMB->DataCount = cpu_to_le32(data_count);
3816 pSMB->TotalDataCount = pSMB->DataCount;
3817 pSMB->MaxParameterCount = cpu_to_le32(4);
3818 pSMB->MaxDataCount = cpu_to_le32(16384);
3819 pSMB->ParameterCount = cpu_to_le32(param_count);
3820 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3821 pSMB->TotalParameterCount = pSMB->ParameterCount;
3822 pSMB->DataOffset = cpu_to_le32(data_offset);
3823 pSMB->SetupCount = 0;
3824 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3825 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3826
3827 pSMB->Fid = fid; /* file handle always le */
3828 pSMB->Reserved2 = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003829 pSMB->AclFlags = cpu_to_le32(aclflag);
Steve French97837582007-12-31 07:47:21 +00003830
3831 if (pntsd && acllen) {
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003832 memcpy((char *)pSMBr + offsetof(struct smb_hdr, Protocol) +
3833 data_offset, pntsd, acllen);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003834 inc_rfc1001_len(pSMB, byte_count + data_count);
Steve French97837582007-12-31 07:47:21 +00003835 } else
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003836 inc_rfc1001_len(pSMB, byte_count);
Steve French97837582007-12-31 07:47:21 +00003837
3838 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3839 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3840
Joe Perchesb6b38f72010-04-21 03:50:45 +00003841 cFYI(1, "SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00003842 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003843 cFYI(1, "Set CIFS ACL returned %d", rc);
Steve French97837582007-12-31 07:47:21 +00003844 cifs_buf_release(pSMB);
3845
3846 if (rc == -EAGAIN)
3847 goto setCifsAclRetry;
3848
3849 return (rc);
3850}
3851
Jeff Layton79df1ba2010-12-06 12:52:08 -05003852#endif /* CONFIG_CIFS_ACL */
Steve French0a4b92c2006-01-12 15:44:21 -08003853
Steve French6b8edfe2005-08-23 20:26:03 -07003854/* Legacy Query Path Information call for lookup to old servers such
3855 as Win9x/WinME */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003856int
3857SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon,
3858 const char *search_name, FILE_ALL_INFO *data,
3859 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003860{
Steve Frenchad7a2922008-02-07 23:25:02 +00003861 QUERY_INFORMATION_REQ *pSMB;
3862 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003863 int rc = 0;
3864 int bytes_returned;
3865 int name_len;
3866
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003867 cFYI(1, "In SMBQPath path %s", search_name);
Steve French6b8edfe2005-08-23 20:26:03 -07003868QInfRetry:
3869 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003870 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003871 if (rc)
3872 return rc;
3873
3874 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3875 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003876 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003877 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06003878 remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003879 name_len++; /* trailing null */
3880 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003881 } else {
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003882 name_len = strnlen(search_name, PATH_MAX);
Steve French6b8edfe2005-08-23 20:26:03 -07003883 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003884 strncpy(pSMB->FileName, search_name, name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07003885 }
3886 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003887 name_len++; /* account for buffer type byte */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003888 inc_rfc1001_len(pSMB, (__u16)name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07003889 pSMB->ByteCount = cpu_to_le16(name_len);
3890
3891 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003892 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003893 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003894 cFYI(1, "Send error in QueryInfo = %d", rc);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003895 } else if (data) {
Steve French1bd5bbc2006-09-28 03:35:57 +00003896 struct timespec ts;
3897 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00003898
3899 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003900 /* BB FIXME - add time zone adjustment BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003901 memset(data, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003902 ts.tv_nsec = 0;
3903 ts.tv_sec = time;
3904 /* decode time fields */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003905 data->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
3906 data->LastWriteTime = data->ChangeTime;
3907 data->LastAccessTime = 0;
3908 data->AllocationSize =
Steve French70ca7342005-09-22 16:32:06 -07003909 cpu_to_le64(le32_to_cpu(pSMBr->size));
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003910 data->EndOfFile = data->AllocationSize;
3911 data->Attributes =
Steve French70ca7342005-09-22 16:32:06 -07003912 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003913 } else
3914 rc = -EIO; /* bad buffer passed in */
3915
3916 cifs_buf_release(pSMB);
3917
3918 if (rc == -EAGAIN)
3919 goto QInfRetry;
3920
3921 return rc;
3922}
3923
Jeff Laytonbcd53572010-02-12 07:44:16 -05003924int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003925CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonbcd53572010-02-12 07:44:16 -05003926 u16 netfid, FILE_ALL_INFO *pFindData)
3927{
3928 struct smb_t2_qfi_req *pSMB = NULL;
3929 struct smb_t2_qfi_rsp *pSMBr = NULL;
3930 int rc = 0;
3931 int bytes_returned;
3932 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07003933
Jeff Laytonbcd53572010-02-12 07:44:16 -05003934QFileInfoRetry:
3935 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3936 (void **) &pSMBr);
3937 if (rc)
3938 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07003939
Jeff Laytonbcd53572010-02-12 07:44:16 -05003940 params = 2 /* level */ + 2 /* fid */;
3941 pSMB->t2.TotalDataCount = 0;
3942 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3943 /* BB find exact max data count below from sess structure BB */
3944 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3945 pSMB->t2.MaxSetupCount = 0;
3946 pSMB->t2.Reserved = 0;
3947 pSMB->t2.Flags = 0;
3948 pSMB->t2.Timeout = 0;
3949 pSMB->t2.Reserved2 = 0;
3950 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3951 Fid) - 4);
3952 pSMB->t2.DataCount = 0;
3953 pSMB->t2.DataOffset = 0;
3954 pSMB->t2.SetupCount = 1;
3955 pSMB->t2.Reserved3 = 0;
3956 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3957 byte_count = params + 1 /* pad */ ;
3958 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3959 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3960 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3961 pSMB->Pad = 0;
3962 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003963 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003964
3965 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3966 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3967 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00003968 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003969 } else { /* decode response */
3970 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3971
3972 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3973 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04003974 else if (get_bcc(&pSMBr->hdr) < 40)
Jeff Laytonbcd53572010-02-12 07:44:16 -05003975 rc = -EIO; /* bad smb */
3976 else if (pFindData) {
3977 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3978 memcpy((char *) pFindData,
3979 (char *) &pSMBr->hdr.Protocol +
3980 data_offset, sizeof(FILE_ALL_INFO));
3981 } else
3982 rc = -ENOMEM;
3983 }
3984 cifs_buf_release(pSMB);
3985 if (rc == -EAGAIN)
3986 goto QFileInfoRetry;
3987
3988 return rc;
3989}
Steve French6b8edfe2005-08-23 20:26:03 -07003990
Linus Torvalds1da177e2005-04-16 15:20:36 -07003991int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003992CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003993 const char *search_name, FILE_ALL_INFO *data,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003994 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003995 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003996{
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003997 /* level 263 SMB_QUERY_FILE_ALL_INFO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003998 TRANSACTION2_QPI_REQ *pSMB = NULL;
3999 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4000 int rc = 0;
4001 int bytes_returned;
4002 int name_len;
4003 __u16 params, byte_count;
4004
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004005 /* cFYI(1, "In QPathInfo path %s", search_name); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004006QPathInfoRetry:
4007 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4008 (void **) &pSMBr);
4009 if (rc)
4010 return rc;
4011
4012 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4013 name_len =
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004014 cifsConvertToUTF16((__le16 *) pSMB->FileName, search_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06004015 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004016 name_len++; /* trailing null */
4017 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004018 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004019 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004020 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004021 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004022 }
4023
Steve French50c2f752007-07-13 00:33:32 +00004024 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004025 pSMB->TotalDataCount = 0;
4026 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004027 /* BB find exact max SMB PDU from sess structure BB */
4028 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004029 pSMB->MaxSetupCount = 0;
4030 pSMB->Reserved = 0;
4031 pSMB->Flags = 0;
4032 pSMB->Timeout = 0;
4033 pSMB->Reserved2 = 0;
4034 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004035 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004036 pSMB->DataCount = 0;
4037 pSMB->DataOffset = 0;
4038 pSMB->SetupCount = 1;
4039 pSMB->Reserved3 = 0;
4040 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4041 byte_count = params + 1 /* pad */ ;
4042 pSMB->TotalParameterCount = cpu_to_le16(params);
4043 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00004044 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004045 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
4046 else
4047 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004048 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004049 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004050 pSMB->ByteCount = cpu_to_le16(byte_count);
4051
4052 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4053 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4054 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004055 cFYI(1, "Send error in QPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004056 } else { /* decode response */
4057 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4058
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004059 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4060 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004061 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004062 rc = -EIO; /* bad smb */
Jeff Layton820a8032011-05-04 08:05:26 -04004063 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
Steve French50c2f752007-07-13 00:33:32 +00004064 rc = -EIO; /* 24 or 26 expected but we do not read
4065 last field */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004066 else if (data) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004067 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004068 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00004069
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004070 /*
4071 * On legacy responses we do not read the last field,
4072 * EAsize, fortunately since it varies by subdialect and
4073 * also note it differs on Set vs Get, ie two bytes or 4
4074 * bytes depending but we don't care here.
4075 */
Steve Frenchad7a2922008-02-07 23:25:02 +00004076 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004077 size = sizeof(FILE_INFO_STANDARD);
4078 else
4079 size = sizeof(FILE_ALL_INFO);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004080 memcpy((char *) data, (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004081 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004082 } else
4083 rc = -ENOMEM;
4084 }
4085 cifs_buf_release(pSMB);
4086 if (rc == -EAGAIN)
4087 goto QPathInfoRetry;
4088
4089 return rc;
4090}
4091
4092int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004093CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004094 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
4095{
4096 struct smb_t2_qfi_req *pSMB = NULL;
4097 struct smb_t2_qfi_rsp *pSMBr = NULL;
4098 int rc = 0;
4099 int bytes_returned;
4100 __u16 params, byte_count;
4101
4102UnixQFileInfoRetry:
4103 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4104 (void **) &pSMBr);
4105 if (rc)
4106 return rc;
4107
4108 params = 2 /* level */ + 2 /* fid */;
4109 pSMB->t2.TotalDataCount = 0;
4110 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4111 /* BB find exact max data count below from sess structure BB */
4112 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4113 pSMB->t2.MaxSetupCount = 0;
4114 pSMB->t2.Reserved = 0;
4115 pSMB->t2.Flags = 0;
4116 pSMB->t2.Timeout = 0;
4117 pSMB->t2.Reserved2 = 0;
4118 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4119 Fid) - 4);
4120 pSMB->t2.DataCount = 0;
4121 pSMB->t2.DataOffset = 0;
4122 pSMB->t2.SetupCount = 1;
4123 pSMB->t2.Reserved3 = 0;
4124 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4125 byte_count = params + 1 /* pad */ ;
4126 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4127 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4128 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4129 pSMB->Pad = 0;
4130 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004131 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004132
4133 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4134 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4135 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00004136 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004137 } else { /* decode response */
4138 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4139
Jeff Layton820a8032011-05-04 08:05:26 -04004140 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004141 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response. "
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004142 "Unix Extensions can be disabled on mount "
Steve Frenchf19159d2010-04-21 04:12:10 +00004143 "by specifying the nosfu mount option.");
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004144 rc = -EIO; /* bad smb */
4145 } else {
4146 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4147 memcpy((char *) pFindData,
4148 (char *) &pSMBr->hdr.Protocol +
4149 data_offset,
4150 sizeof(FILE_UNIX_BASIC_INFO));
4151 }
4152 }
4153
4154 cifs_buf_release(pSMB);
4155 if (rc == -EAGAIN)
4156 goto UnixQFileInfoRetry;
4157
4158 return rc;
4159}
4160
4161int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004162CIFSSMBUnixQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004163 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00004164 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07004165 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004166{
4167/* SMB_QUERY_FILE_UNIX_BASIC */
4168 TRANSACTION2_QPI_REQ *pSMB = NULL;
4169 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4170 int rc = 0;
4171 int bytes_returned = 0;
4172 int name_len;
4173 __u16 params, byte_count;
4174
Joe Perchesb6b38f72010-04-21 03:50:45 +00004175 cFYI(1, "In QPathInfo (Unix) the path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004176UnixQPathInfoRetry:
4177 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4178 (void **) &pSMBr);
4179 if (rc)
4180 return rc;
4181
4182 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4183 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004184 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4185 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004186 name_len++; /* trailing null */
4187 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004188 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004189 name_len = strnlen(searchName, PATH_MAX);
4190 name_len++; /* trailing null */
4191 strncpy(pSMB->FileName, searchName, name_len);
4192 }
4193
Steve French50c2f752007-07-13 00:33:32 +00004194 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004195 pSMB->TotalDataCount = 0;
4196 pSMB->MaxParameterCount = cpu_to_le16(2);
4197 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00004198 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004199 pSMB->MaxSetupCount = 0;
4200 pSMB->Reserved = 0;
4201 pSMB->Flags = 0;
4202 pSMB->Timeout = 0;
4203 pSMB->Reserved2 = 0;
4204 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004205 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004206 pSMB->DataCount = 0;
4207 pSMB->DataOffset = 0;
4208 pSMB->SetupCount = 1;
4209 pSMB->Reserved3 = 0;
4210 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4211 byte_count = params + 1 /* pad */ ;
4212 pSMB->TotalParameterCount = cpu_to_le16(params);
4213 pSMB->ParameterCount = pSMB->TotalParameterCount;
4214 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4215 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004216 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004217 pSMB->ByteCount = cpu_to_le16(byte_count);
4218
4219 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4220 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4221 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004222 cFYI(1, "Send error in QPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004223 } else { /* decode response */
4224 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4225
Jeff Layton820a8032011-05-04 08:05:26 -04004226 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004227 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response. "
Steve French1e71f252007-09-20 15:30:07 +00004228 "Unix Extensions can be disabled on mount "
Joe Perchesb6b38f72010-04-21 03:50:45 +00004229 "by specifying the nosfu mount option.");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004230 rc = -EIO; /* bad smb */
4231 } else {
4232 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4233 memcpy((char *) pFindData,
4234 (char *) &pSMBr->hdr.Protocol +
4235 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00004236 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004237 }
4238 }
4239 cifs_buf_release(pSMB);
4240 if (rc == -EAGAIN)
4241 goto UnixQPathInfoRetry;
4242
4243 return rc;
4244}
4245
Linus Torvalds1da177e2005-04-16 15:20:36 -07004246/* xid, tcon, searchName and codepage are input parms, rest are returned */
4247int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004248CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004249 const char *searchName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004250 const struct nls_table *nls_codepage,
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004251 __u16 *pnetfid, __u16 search_flags,
Steve French50c2f752007-07-13 00:33:32 +00004252 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004253{
4254/* level 257 SMB_ */
4255 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
4256 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004257 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004258 int rc = 0;
4259 int bytes_returned = 0;
4260 int name_len;
4261 __u16 params, byte_count;
4262
Joe Perchesb6b38f72010-04-21 03:50:45 +00004263 cFYI(1, "In FindFirst for %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004264
4265findFirstRetry:
4266 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4267 (void **) &pSMBr);
4268 if (rc)
4269 return rc;
4270
4271 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4272 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004273 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4274 PATH_MAX, nls_codepage, remap);
Steve French737b7582005-04-28 22:41:06 -07004275 /* We can not add the asterik earlier in case
4276 it got remapped to 0xF03A as if it were part of the
4277 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004278 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07004279 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07004280 pSMB->FileName[name_len+1] = 0;
4281 pSMB->FileName[name_len+2] = '*';
4282 pSMB->FileName[name_len+3] = 0;
4283 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004284 pSMB->FileName[name_len] = 0; /* null terminate just in case */
4285 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07004286 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004287 } else { /* BB add check for overrun of SMB buf BB */
4288 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004289/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00004290 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004291 free buffer exit; BB */
4292 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07004293 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07004294 pSMB->FileName[name_len+1] = '*';
4295 pSMB->FileName[name_len+2] = 0;
4296 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004297 }
4298
4299 params = 12 + name_len /* includes null */ ;
4300 pSMB->TotalDataCount = 0; /* no EAs */
4301 pSMB->MaxParameterCount = cpu_to_le16(10);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004302 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004303 pSMB->MaxSetupCount = 0;
4304 pSMB->Reserved = 0;
4305 pSMB->Flags = 0;
4306 pSMB->Timeout = 0;
4307 pSMB->Reserved2 = 0;
4308 byte_count = params + 1 /* pad */ ;
4309 pSMB->TotalParameterCount = cpu_to_le16(params);
4310 pSMB->ParameterCount = pSMB->TotalParameterCount;
4311 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00004312 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
4313 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004314 pSMB->DataCount = 0;
4315 pSMB->DataOffset = 0;
4316 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
4317 pSMB->Reserved3 = 0;
4318 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
4319 pSMB->SearchAttributes =
4320 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
4321 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00004322 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004323 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004324 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4325
4326 /* BB what should we set StorageType to? Does it matter? BB */
4327 pSMB->SearchStorageType = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004328 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004329 pSMB->ByteCount = cpu_to_le16(byte_count);
4330
4331 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4332 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004333 cifs_stats_inc(&tcon->stats.cifs_stats.num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004334
Steve French88274812006-03-09 22:21:45 +00004335 if (rc) {/* BB add logic to retry regular search if Unix search
4336 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004337 /* BB Add code to handle unsupported level rc */
Joe Perchesb6b38f72010-04-21 03:50:45 +00004338 cFYI(1, "Error in FindFirst = %d", rc);
Steve French1982c342005-08-17 12:38:22 -07004339
Steve French88274812006-03-09 22:21:45 +00004340 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004341
4342 /* BB eventually could optimize out free and realloc of buf */
4343 /* for this case */
4344 if (rc == -EAGAIN)
4345 goto findFirstRetry;
4346 } else { /* decode response */
4347 /* BB remember to free buffer if error BB */
4348 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00004349 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004350 unsigned int lnoff;
4351
Linus Torvalds1da177e2005-04-16 15:20:36 -07004352 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004353 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004354 else
Steve French4b18f2a2008-04-29 00:06:05 +00004355 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004356
4357 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004358 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00004359 psrch_inf->srch_entries_start =
4360 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004361 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004362 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
4363 le16_to_cpu(pSMBr->t2.ParameterOffset));
4364
Steve French790fe572007-07-07 19:25:05 +00004365 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004366 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004367 else
Steve French4b18f2a2008-04-29 00:06:05 +00004368 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004369
Steve French50c2f752007-07-13 00:33:32 +00004370 psrch_inf->entries_in_buffer =
4371 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00004372 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004373 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004374 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004375 if (CIFSMaxBufSize < lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004376 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00004377 psrch_inf->last_entry = NULL;
4378 return rc;
4379 }
4380
Steve French0752f152008-10-07 20:03:33 +00004381 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00004382 lnoff;
4383
Linus Torvalds1da177e2005-04-16 15:20:36 -07004384 *pnetfid = parms->SearchHandle;
4385 } else {
4386 cifs_buf_release(pSMB);
4387 }
4388 }
4389
4390 return rc;
4391}
4392
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004393int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
4394 __u16 searchHandle, __u16 search_flags,
4395 struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004396{
4397 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
4398 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004399 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004400 char *response_data;
4401 int rc = 0;
Jeff Layton9438fab2011-08-23 07:21:28 -04004402 int bytes_returned;
4403 unsigned int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004404 __u16 params, byte_count;
4405
Joe Perchesb6b38f72010-04-21 03:50:45 +00004406 cFYI(1, "In FindNext");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004407
Steve French4b18f2a2008-04-29 00:06:05 +00004408 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004409 return -ENOENT;
4410
4411 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4412 (void **) &pSMBr);
4413 if (rc)
4414 return rc;
4415
Steve French50c2f752007-07-13 00:33:32 +00004416 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004417 byte_count = 0;
4418 pSMB->TotalDataCount = 0; /* no EAs */
4419 pSMB->MaxParameterCount = cpu_to_le16(8);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004420 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004421 pSMB->MaxSetupCount = 0;
4422 pSMB->Reserved = 0;
4423 pSMB->Flags = 0;
4424 pSMB->Timeout = 0;
4425 pSMB->Reserved2 = 0;
4426 pSMB->ParameterOffset = cpu_to_le16(
4427 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
4428 pSMB->DataCount = 0;
4429 pSMB->DataOffset = 0;
4430 pSMB->SetupCount = 1;
4431 pSMB->Reserved3 = 0;
4432 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
4433 pSMB->SearchHandle = searchHandle; /* always kept as le */
4434 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00004435 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004436 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4437 pSMB->ResumeKey = psrch_inf->resume_key;
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004438 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004439
4440 name_len = psrch_inf->resume_name_len;
4441 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00004442 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004443 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
4444 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07004445 /* 14 byte parm len above enough for 2 byte null terminator */
4446 pSMB->ResumeFileName[name_len] = 0;
4447 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004448 } else {
4449 rc = -EINVAL;
4450 goto FNext2_err_exit;
4451 }
4452 byte_count = params + 1 /* pad */ ;
4453 pSMB->TotalParameterCount = cpu_to_le16(params);
4454 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004455 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004456 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004457
Linus Torvalds1da177e2005-04-16 15:20:36 -07004458 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4459 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004460 cifs_stats_inc(&tcon->stats.cifs_stats.num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004461 if (rc) {
4462 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00004463 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07004464 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00004465 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004466 } else
Joe Perchesb6b38f72010-04-21 03:50:45 +00004467 cFYI(1, "FindNext returned = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004468 } else { /* decode response */
4469 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00004470
Steve French790fe572007-07-07 19:25:05 +00004471 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004472 unsigned int lnoff;
4473
Linus Torvalds1da177e2005-04-16 15:20:36 -07004474 /* BB fixme add lock for file (srch_info) struct here */
4475 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004476 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004477 else
Steve French4b18f2a2008-04-29 00:06:05 +00004478 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004479 response_data = (char *) &pSMBr->hdr.Protocol +
4480 le16_to_cpu(pSMBr->t2.ParameterOffset);
4481 parms = (T2_FNEXT_RSP_PARMS *)response_data;
4482 response_data = (char *)&pSMBr->hdr.Protocol +
4483 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00004484 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00004485 cifs_small_buf_release(
4486 psrch_inf->ntwrk_buf_start);
4487 else
4488 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004489 psrch_inf->srch_entries_start = response_data;
4490 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004491 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00004492 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004493 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004494 else
Steve French4b18f2a2008-04-29 00:06:05 +00004495 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00004496 psrch_inf->entries_in_buffer =
4497 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004498 psrch_inf->index_of_last_entry +=
4499 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004500 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004501 if (CIFSMaxBufSize < lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004502 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00004503 psrch_inf->last_entry = NULL;
4504 return rc;
4505 } else
4506 psrch_inf->last_entry =
4507 psrch_inf->srch_entries_start + lnoff;
4508
Joe Perchesb6b38f72010-04-21 03:50:45 +00004509/* cFYI(1, "fnxt2 entries in buf %d index_of_last %d",
4510 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004511
4512 /* BB fixme add unlock here */
4513 }
4514
4515 }
4516
4517 /* BB On error, should we leave previous search buf (and count and
4518 last entry fields) intact or free the previous one? */
4519
4520 /* Note: On -EAGAIN error only caller can retry on handle based calls
4521 since file handle passed in no longer valid */
4522FNext2_err_exit:
4523 if (rc != 0)
4524 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004525 return rc;
4526}
4527
4528int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004529CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004530 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004531{
4532 int rc = 0;
4533 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004534
Joe Perchesb6b38f72010-04-21 03:50:45 +00004535 cFYI(1, "In CIFSSMBFindClose");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004536 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
4537
4538 /* no sense returning error if session restarted
4539 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00004540 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004541 return 0;
4542 if (rc)
4543 return rc;
4544
Linus Torvalds1da177e2005-04-16 15:20:36 -07004545 pSMB->FileID = searchHandle;
4546 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04004547 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004548 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00004549 cERROR(1, "Send error in FindClose = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00004550
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004551 cifs_stats_inc(&tcon->stats.cifs_stats.num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004552
4553 /* Since session is dead, search handle closed on server already */
4554 if (rc == -EAGAIN)
4555 rc = 0;
4556
4557 return rc;
4558}
4559
Linus Torvalds1da177e2005-04-16 15:20:36 -07004560int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004561CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004562 const char *search_name, __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00004563 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004564{
4565 int rc = 0;
4566 TRANSACTION2_QPI_REQ *pSMB = NULL;
4567 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4568 int name_len, bytes_returned;
4569 __u16 params, byte_count;
4570
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004571 cFYI(1, "In GetSrvInodeNum for %s", search_name);
Steve French790fe572007-07-07 19:25:05 +00004572 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00004573 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004574
4575GetInodeNumberRetry:
4576 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004577 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004578 if (rc)
4579 return rc;
4580
Linus Torvalds1da177e2005-04-16 15:20:36 -07004581 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4582 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004583 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004584 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004585 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004586 name_len++; /* trailing null */
4587 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004588 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004589 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004590 name_len++; /* trailing null */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004591 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004592 }
4593
4594 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4595 pSMB->TotalDataCount = 0;
4596 pSMB->MaxParameterCount = cpu_to_le16(2);
4597 /* BB find exact max data count below from sess structure BB */
4598 pSMB->MaxDataCount = cpu_to_le16(4000);
4599 pSMB->MaxSetupCount = 0;
4600 pSMB->Reserved = 0;
4601 pSMB->Flags = 0;
4602 pSMB->Timeout = 0;
4603 pSMB->Reserved2 = 0;
4604 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004605 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004606 pSMB->DataCount = 0;
4607 pSMB->DataOffset = 0;
4608 pSMB->SetupCount = 1;
4609 pSMB->Reserved3 = 0;
4610 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4611 byte_count = params + 1 /* pad */ ;
4612 pSMB->TotalParameterCount = cpu_to_le16(params);
4613 pSMB->ParameterCount = pSMB->TotalParameterCount;
4614 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4615 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004616 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004617 pSMB->ByteCount = cpu_to_le16(byte_count);
4618
4619 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4620 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4621 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004622 cFYI(1, "error %d in QueryInternalInfo", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004623 } else {
4624 /* decode response */
4625 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004626 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04004627 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004628 /* If rc should we check for EOPNOSUPP and
4629 disable the srvino flag? or in caller? */
4630 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00004631 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004632 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4633 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00004634 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004635 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00004636 if (count < 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004637 cFYI(1, "Illegal size ret in QryIntrnlInf");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004638 rc = -EIO;
4639 goto GetInodeNumOut;
4640 }
4641 pfinfo = (struct file_internal_info *)
4642 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00004643 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004644 }
4645 }
4646GetInodeNumOut:
4647 cifs_buf_release(pSMB);
4648 if (rc == -EAGAIN)
4649 goto GetInodeNumberRetry;
4650 return rc;
4651}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004652
Igor Mammedovfec45852008-05-16 13:06:30 +04004653/* parses DFS refferal V3 structure
4654 * caller is responsible for freeing target_nodes
4655 * returns:
4656 * on success - 0
4657 * on failure - errno
4658 */
4659static int
Steve Frencha1fe78f2008-05-16 18:48:38 +00004660parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
Igor Mammedovfec45852008-05-16 13:06:30 +04004661 unsigned int *num_of_nodes,
4662 struct dfs_info3_param **target_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004663 const struct nls_table *nls_codepage, int remap,
4664 const char *searchName)
Igor Mammedovfec45852008-05-16 13:06:30 +04004665{
4666 int i, rc = 0;
4667 char *data_end;
4668 bool is_unicode;
4669 struct dfs_referral_level_3 *ref;
4670
Harvey Harrison5ca33c62008-07-23 17:45:58 -07004671 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4672 is_unicode = true;
4673 else
4674 is_unicode = false;
Igor Mammedovfec45852008-05-16 13:06:30 +04004675 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
4676
4677 if (*num_of_nodes < 1) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004678 cERROR(1, "num_referrals: must be at least > 0,"
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004679 "but we get num_referrals = %d", *num_of_nodes);
Igor Mammedovfec45852008-05-16 13:06:30 +04004680 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004681 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004682 }
4683
4684 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
Al Viro1d92cfd2008-06-02 10:59:02 +01004685 if (ref->VersionNumber != cpu_to_le16(3)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004686 cERROR(1, "Referrals of V%d version are not supported,"
4687 "should be V3", le16_to_cpu(ref->VersionNumber));
Igor Mammedovfec45852008-05-16 13:06:30 +04004688 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004689 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004690 }
4691
4692 /* get the upper boundary of the resp buffer */
4693 data_end = (char *)(&(pSMBr->PathConsumed)) +
4694 le16_to_cpu(pSMBr->t2.DataCount);
4695
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004696 cFYI(1, "num_referrals: %d dfs flags: 0x%x ...",
Igor Mammedovfec45852008-05-16 13:06:30 +04004697 *num_of_nodes,
Joe Perchesb6b38f72010-04-21 03:50:45 +00004698 le32_to_cpu(pSMBr->DFSFlags));
Igor Mammedovfec45852008-05-16 13:06:30 +04004699
4700 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
4701 *num_of_nodes, GFP_KERNEL);
4702 if (*target_nodes == NULL) {
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004703 cERROR(1, "Failed to allocate buffer for target_nodes");
Igor Mammedovfec45852008-05-16 13:06:30 +04004704 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004705 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004706 }
4707
Daniel Mack3ad2f3f2010-02-03 08:01:28 +08004708 /* collect necessary data from referrals */
Igor Mammedovfec45852008-05-16 13:06:30 +04004709 for (i = 0; i < *num_of_nodes; i++) {
4710 char *temp;
4711 int max_len;
4712 struct dfs_info3_param *node = (*target_nodes)+i;
4713
Steve French0e0d2cf2009-05-01 05:27:32 +00004714 node->flags = le32_to_cpu(pSMBr->DFSFlags);
Igor Mammedov2c556082008-10-23 13:58:42 +04004715 if (is_unicode) {
Jeff Layton331c3132008-12-17 06:31:53 -05004716 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4717 GFP_KERNEL);
Steve French2920ee22009-08-31 15:27:26 +00004718 if (tmp == NULL) {
4719 rc = -ENOMEM;
4720 goto parse_DFS_referrals_exit;
4721 }
Steve Frenchacbbb762012-01-18 22:32:33 -06004722 cifsConvertToUTF16((__le16 *) tmp, searchName,
4723 PATH_MAX, nls_codepage, remap);
4724 node->path_consumed = cifs_utf16_bytes(tmp,
Jeff Layton69f801f2009-04-30 06:46:32 -04004725 le16_to_cpu(pSMBr->PathConsumed),
Igor Mammedov2c556082008-10-23 13:58:42 +04004726 nls_codepage);
4727 kfree(tmp);
4728 } else
4729 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4730
Igor Mammedovfec45852008-05-16 13:06:30 +04004731 node->server_type = le16_to_cpu(ref->ServerType);
4732 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4733
4734 /* copy DfsPath */
4735 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4736 max_len = data_end - temp;
Steve Frenchacbbb762012-01-18 22:32:33 -06004737 node->path_name = cifs_strndup_from_utf16(temp, max_len,
4738 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004739 if (!node->path_name) {
4740 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004741 goto parse_DFS_referrals_exit;
Jeff Layton066ce682009-04-30 07:16:14 -04004742 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004743
4744 /* copy link target UNC */
4745 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4746 max_len = data_end - temp;
Steve Frenchacbbb762012-01-18 22:32:33 -06004747 node->node_name = cifs_strndup_from_utf16(temp, max_len,
4748 is_unicode, nls_codepage);
Stefan Metzmacherd8f27992012-05-04 00:19:28 +02004749 if (!node->node_name) {
Jeff Laytond8e2f532009-05-14 07:46:59 -04004750 rc = -ENOMEM;
Stefan Metzmacherd8f27992012-05-04 00:19:28 +02004751 goto parse_DFS_referrals_exit;
4752 }
4753
4754 ref++;
Igor Mammedovfec45852008-05-16 13:06:30 +04004755 }
4756
Steve Frencha1fe78f2008-05-16 18:48:38 +00004757parse_DFS_referrals_exit:
Igor Mammedovfec45852008-05-16 13:06:30 +04004758 if (rc) {
4759 free_dfs_info_array(*target_nodes, *num_of_nodes);
4760 *target_nodes = NULL;
4761 *num_of_nodes = 0;
4762 }
4763 return rc;
4764}
4765
Linus Torvalds1da177e2005-04-16 15:20:36 -07004766int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004767CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004768 const char *search_name, struct dfs_info3_param **target_nodes,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004769 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004770 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004771{
4772/* TRANS2_GET_DFS_REFERRAL */
4773 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4774 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004775 int rc = 0;
4776 int bytes_returned;
4777 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004778 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004779 *num_of_nodes = 0;
4780 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004781
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004782 cFYI(1, "In GetDFSRefer the path %s", search_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004783 if (ses == NULL)
4784 return -ENODEV;
4785getDFSRetry:
4786 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4787 (void **) &pSMBr);
4788 if (rc)
4789 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004790
4791 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004792 but should never be null here anyway */
Pavel Shilovsky88257362012-05-23 14:01:59 +04004793 pSMB->hdr.Mid = get_next_mid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004794 pSMB->hdr.Tid = ses->ipc_tid;
4795 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004796 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004797 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004798 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004799 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004800
4801 if (ses->capabilities & CAP_UNICODE) {
4802 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4803 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004804 cifsConvertToUTF16((__le16 *) pSMB->RequestFileName,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004805 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004806 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004807 name_len++; /* trailing null */
4808 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004809 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004810 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004811 name_len++; /* trailing null */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004812 strncpy(pSMB->RequestFileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004813 }
4814
Steve French790fe572007-07-07 19:25:05 +00004815 if (ses->server) {
Steve French96daf2b2011-05-27 04:34:02 +00004816 if (ses->server->sec_mode &
Steve French1a4e15a2006-10-12 21:33:51 +00004817 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4818 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4819 }
4820
Steve French50c2f752007-07-13 00:33:32 +00004821 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004822
Linus Torvalds1da177e2005-04-16 15:20:36 -07004823 params = 2 /* level */ + name_len /*includes null */ ;
4824 pSMB->TotalDataCount = 0;
4825 pSMB->DataCount = 0;
4826 pSMB->DataOffset = 0;
4827 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004828 /* BB find exact max SMB PDU from sess structure BB */
4829 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004830 pSMB->MaxSetupCount = 0;
4831 pSMB->Reserved = 0;
4832 pSMB->Flags = 0;
4833 pSMB->Timeout = 0;
4834 pSMB->Reserved2 = 0;
4835 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004836 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004837 pSMB->SetupCount = 1;
4838 pSMB->Reserved3 = 0;
4839 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4840 byte_count = params + 3 /* pad */ ;
4841 pSMB->ParameterCount = cpu_to_le16(params);
4842 pSMB->TotalParameterCount = pSMB->ParameterCount;
4843 pSMB->MaxReferralLevel = cpu_to_le16(3);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004844 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004845 pSMB->ByteCount = cpu_to_le16(byte_count);
4846
4847 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4848 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4849 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004850 cFYI(1, "Send error in GetDFSRefer = %d", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004851 goto GetDFSRefExit;
4852 }
4853 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004854
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004855 /* BB Also check if enough total bytes returned? */
Jeff Layton820a8032011-05-04 08:05:26 -04004856 if (rc || get_bcc(&pSMBr->hdr) < 17) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004857 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004858 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004859 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004860
Joe Perchesb6b38f72010-04-21 03:50:45 +00004861 cFYI(1, "Decoding GetDFSRefer response BCC: %d Offset %d",
Jeff Layton820a8032011-05-04 08:05:26 -04004862 get_bcc(&pSMBr->hdr),
Joe Perchesb6b38f72010-04-21 03:50:45 +00004863 le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04004864
4865 /* parse returned result into more usable form */
Steve Frencha1fe78f2008-05-16 18:48:38 +00004866 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004867 target_nodes, nls_codepage, remap,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004868 search_name);
Igor Mammedovfec45852008-05-16 13:06:30 +04004869
Linus Torvalds1da177e2005-04-16 15:20:36 -07004870GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004871 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004872
4873 if (rc == -EAGAIN)
4874 goto getDFSRetry;
4875
4876 return rc;
4877}
4878
Steve French20962432005-09-21 22:05:57 -07004879/* Query File System Info such as free space to old servers such as Win 9x */
4880int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004881SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4882 struct kstatfs *FSData)
Steve French20962432005-09-21 22:05:57 -07004883{
4884/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4885 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4886 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4887 FILE_SYSTEM_ALLOC_INFO *response_data;
4888 int rc = 0;
4889 int bytes_returned = 0;
4890 __u16 params, byte_count;
4891
Joe Perchesb6b38f72010-04-21 03:50:45 +00004892 cFYI(1, "OldQFSInfo");
Steve French20962432005-09-21 22:05:57 -07004893oldQFSInfoRetry:
4894 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4895 (void **) &pSMBr);
4896 if (rc)
4897 return rc;
Steve French20962432005-09-21 22:05:57 -07004898
4899 params = 2; /* level */
4900 pSMB->TotalDataCount = 0;
4901 pSMB->MaxParameterCount = cpu_to_le16(2);
4902 pSMB->MaxDataCount = cpu_to_le16(1000);
4903 pSMB->MaxSetupCount = 0;
4904 pSMB->Reserved = 0;
4905 pSMB->Flags = 0;
4906 pSMB->Timeout = 0;
4907 pSMB->Reserved2 = 0;
4908 byte_count = params + 1 /* pad */ ;
4909 pSMB->TotalParameterCount = cpu_to_le16(params);
4910 pSMB->ParameterCount = pSMB->TotalParameterCount;
4911 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4912 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4913 pSMB->DataCount = 0;
4914 pSMB->DataOffset = 0;
4915 pSMB->SetupCount = 1;
4916 pSMB->Reserved3 = 0;
4917 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4918 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004919 inc_rfc1001_len(pSMB, byte_count);
Steve French20962432005-09-21 22:05:57 -07004920 pSMB->ByteCount = cpu_to_le16(byte_count);
4921
4922 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4923 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4924 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004925 cFYI(1, "Send error in QFSInfo = %d", rc);
Steve French20962432005-09-21 22:05:57 -07004926 } else { /* decode response */
4927 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4928
Jeff Layton820a8032011-05-04 08:05:26 -04004929 if (rc || get_bcc(&pSMBr->hdr) < 18)
Steve French20962432005-09-21 22:05:57 -07004930 rc = -EIO; /* bad smb */
4931 else {
4932 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004933 cFYI(1, "qfsinf resp BCC: %d Offset %d",
Jeff Layton820a8032011-05-04 08:05:26 -04004934 get_bcc(&pSMBr->hdr), data_offset);
Steve French20962432005-09-21 22:05:57 -07004935
Steve French50c2f752007-07-13 00:33:32 +00004936 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004937 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4938 FSData->f_bsize =
4939 le16_to_cpu(response_data->BytesPerSector) *
4940 le32_to_cpu(response_data->
4941 SectorsPerAllocationUnit);
4942 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004943 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004944 FSData->f_bfree = FSData->f_bavail =
4945 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004946 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
4947 (unsigned long long)FSData->f_blocks,
4948 (unsigned long long)FSData->f_bfree,
4949 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07004950 }
4951 }
4952 cifs_buf_release(pSMB);
4953
4954 if (rc == -EAGAIN)
4955 goto oldQFSInfoRetry;
4956
4957 return rc;
4958}
4959
Linus Torvalds1da177e2005-04-16 15:20:36 -07004960int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004961CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4962 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004963{
4964/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4965 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4966 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4967 FILE_SYSTEM_INFO *response_data;
4968 int rc = 0;
4969 int bytes_returned = 0;
4970 __u16 params, byte_count;
4971
Joe Perchesb6b38f72010-04-21 03:50:45 +00004972 cFYI(1, "In QFSInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004973QFSInfoRetry:
4974 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4975 (void **) &pSMBr);
4976 if (rc)
4977 return rc;
4978
4979 params = 2; /* level */
4980 pSMB->TotalDataCount = 0;
4981 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004982 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004983 pSMB->MaxSetupCount = 0;
4984 pSMB->Reserved = 0;
4985 pSMB->Flags = 0;
4986 pSMB->Timeout = 0;
4987 pSMB->Reserved2 = 0;
4988 byte_count = params + 1 /* pad */ ;
4989 pSMB->TotalParameterCount = cpu_to_le16(params);
4990 pSMB->ParameterCount = pSMB->TotalParameterCount;
4991 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004992 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004993 pSMB->DataCount = 0;
4994 pSMB->DataOffset = 0;
4995 pSMB->SetupCount = 1;
4996 pSMB->Reserved3 = 0;
4997 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4998 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004999 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005000 pSMB->ByteCount = cpu_to_le16(byte_count);
5001
5002 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5003 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5004 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005005 cFYI(1, "Send error in QFSInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005006 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00005007 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005008
Jeff Layton820a8032011-05-04 08:05:26 -04005009 if (rc || get_bcc(&pSMBr->hdr) < 24)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005010 rc = -EIO; /* bad smb */
5011 else {
5012 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005013
5014 response_data =
5015 (FILE_SYSTEM_INFO
5016 *) (((char *) &pSMBr->hdr.Protocol) +
5017 data_offset);
5018 FSData->f_bsize =
5019 le32_to_cpu(response_data->BytesPerSector) *
5020 le32_to_cpu(response_data->
5021 SectorsPerAllocationUnit);
5022 FSData->f_blocks =
5023 le64_to_cpu(response_data->TotalAllocationUnits);
5024 FSData->f_bfree = FSData->f_bavail =
5025 le64_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesb6b38f72010-04-21 03:50:45 +00005026 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
5027 (unsigned long long)FSData->f_blocks,
5028 (unsigned long long)FSData->f_bfree,
5029 FSData->f_bsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005030 }
5031 }
5032 cifs_buf_release(pSMB);
5033
5034 if (rc == -EAGAIN)
5035 goto QFSInfoRetry;
5036
5037 return rc;
5038}
5039
5040int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005041CIFSSMBQFSAttributeInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005042{
5043/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
5044 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5045 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5046 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
5047 int rc = 0;
5048 int bytes_returned = 0;
5049 __u16 params, byte_count;
5050
Joe Perchesb6b38f72010-04-21 03:50:45 +00005051 cFYI(1, "In QFSAttributeInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005052QFSAttributeRetry:
5053 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5054 (void **) &pSMBr);
5055 if (rc)
5056 return rc;
5057
5058 params = 2; /* level */
5059 pSMB->TotalDataCount = 0;
5060 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005061 /* BB find exact max SMB PDU from sess structure BB */
5062 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005063 pSMB->MaxSetupCount = 0;
5064 pSMB->Reserved = 0;
5065 pSMB->Flags = 0;
5066 pSMB->Timeout = 0;
5067 pSMB->Reserved2 = 0;
5068 byte_count = params + 1 /* pad */ ;
5069 pSMB->TotalParameterCount = cpu_to_le16(params);
5070 pSMB->ParameterCount = pSMB->TotalParameterCount;
5071 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005072 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005073 pSMB->DataCount = 0;
5074 pSMB->DataOffset = 0;
5075 pSMB->SetupCount = 1;
5076 pSMB->Reserved3 = 0;
5077 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5078 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005079 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005080 pSMB->ByteCount = cpu_to_le16(byte_count);
5081
5082 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5083 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5084 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005085 cERROR(1, "Send error in QFSAttributeInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005086 } else { /* decode response */
5087 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5088
Jeff Layton820a8032011-05-04 08:05:26 -04005089 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Steve French50c2f752007-07-13 00:33:32 +00005090 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005091 rc = -EIO; /* bad smb */
5092 } else {
5093 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5094 response_data =
5095 (FILE_SYSTEM_ATTRIBUTE_INFO
5096 *) (((char *) &pSMBr->hdr.Protocol) +
5097 data_offset);
5098 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005099 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005100 }
5101 }
5102 cifs_buf_release(pSMB);
5103
5104 if (rc == -EAGAIN)
5105 goto QFSAttributeRetry;
5106
5107 return rc;
5108}
5109
5110int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005111CIFSSMBQFSDeviceInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005112{
5113/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
5114 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5115 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5116 FILE_SYSTEM_DEVICE_INFO *response_data;
5117 int rc = 0;
5118 int bytes_returned = 0;
5119 __u16 params, byte_count;
5120
Joe Perchesb6b38f72010-04-21 03:50:45 +00005121 cFYI(1, "In QFSDeviceInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005122QFSDeviceRetry:
5123 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5124 (void **) &pSMBr);
5125 if (rc)
5126 return rc;
5127
5128 params = 2; /* level */
5129 pSMB->TotalDataCount = 0;
5130 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005131 /* BB find exact max SMB PDU from sess structure BB */
5132 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005133 pSMB->MaxSetupCount = 0;
5134 pSMB->Reserved = 0;
5135 pSMB->Flags = 0;
5136 pSMB->Timeout = 0;
5137 pSMB->Reserved2 = 0;
5138 byte_count = params + 1 /* pad */ ;
5139 pSMB->TotalParameterCount = cpu_to_le16(params);
5140 pSMB->ParameterCount = pSMB->TotalParameterCount;
5141 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005142 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005143
5144 pSMB->DataCount = 0;
5145 pSMB->DataOffset = 0;
5146 pSMB->SetupCount = 1;
5147 pSMB->Reserved3 = 0;
5148 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5149 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005150 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005151 pSMB->ByteCount = cpu_to_le16(byte_count);
5152
5153 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5154 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5155 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005156 cFYI(1, "Send error in QFSDeviceInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005157 } else { /* decode response */
5158 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5159
Jeff Layton820a8032011-05-04 08:05:26 -04005160 if (rc || get_bcc(&pSMBr->hdr) <
5161 sizeof(FILE_SYSTEM_DEVICE_INFO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005162 rc = -EIO; /* bad smb */
5163 else {
5164 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5165 response_data =
Steve French737b7582005-04-28 22:41:06 -07005166 (FILE_SYSTEM_DEVICE_INFO *)
5167 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07005168 data_offset);
5169 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005170 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005171 }
5172 }
5173 cifs_buf_release(pSMB);
5174
5175 if (rc == -EAGAIN)
5176 goto QFSDeviceRetry;
5177
5178 return rc;
5179}
5180
5181int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005182CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005183{
5184/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
5185 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5186 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5187 FILE_SYSTEM_UNIX_INFO *response_data;
5188 int rc = 0;
5189 int bytes_returned = 0;
5190 __u16 params, byte_count;
5191
Joe Perchesb6b38f72010-04-21 03:50:45 +00005192 cFYI(1, "In QFSUnixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005193QFSUnixRetry:
Jeff Laytonf5695992010-09-29 15:27:08 -04005194 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5195 (void **) &pSMB, (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005196 if (rc)
5197 return rc;
5198
5199 params = 2; /* level */
5200 pSMB->TotalDataCount = 0;
5201 pSMB->DataCount = 0;
5202 pSMB->DataOffset = 0;
5203 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005204 /* BB find exact max SMB PDU from sess structure BB */
5205 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005206 pSMB->MaxSetupCount = 0;
5207 pSMB->Reserved = 0;
5208 pSMB->Flags = 0;
5209 pSMB->Timeout = 0;
5210 pSMB->Reserved2 = 0;
5211 byte_count = params + 1 /* pad */ ;
5212 pSMB->ParameterCount = cpu_to_le16(params);
5213 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005214 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5215 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005216 pSMB->SetupCount = 1;
5217 pSMB->Reserved3 = 0;
5218 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5219 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005220 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005221 pSMB->ByteCount = cpu_to_le16(byte_count);
5222
5223 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5224 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5225 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005226 cERROR(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005227 } else { /* decode response */
5228 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5229
Jeff Layton820a8032011-05-04 08:05:26 -04005230 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005231 rc = -EIO; /* bad smb */
5232 } else {
5233 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5234 response_data =
5235 (FILE_SYSTEM_UNIX_INFO
5236 *) (((char *) &pSMBr->hdr.Protocol) +
5237 data_offset);
5238 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005239 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005240 }
5241 }
5242 cifs_buf_release(pSMB);
5243
5244 if (rc == -EAGAIN)
5245 goto QFSUnixRetry;
5246
5247
5248 return rc;
5249}
5250
Jeremy Allisonac670552005-06-22 17:26:35 -07005251int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005252CIFSSMBSetFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07005253{
5254/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
5255 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
5256 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
5257 int rc = 0;
5258 int bytes_returned = 0;
5259 __u16 params, param_offset, offset, byte_count;
5260
Joe Perchesb6b38f72010-04-21 03:50:45 +00005261 cFYI(1, "In SETFSUnixInfo");
Jeremy Allisonac670552005-06-22 17:26:35 -07005262SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00005263 /* BB switch to small buf init to save memory */
Jeff Laytonf5695992010-09-29 15:27:08 -04005264 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5265 (void **) &pSMB, (void **) &pSMBr);
Jeremy Allisonac670552005-06-22 17:26:35 -07005266 if (rc)
5267 return rc;
5268
5269 params = 4; /* 2 bytes zero followed by info level. */
5270 pSMB->MaxSetupCount = 0;
5271 pSMB->Reserved = 0;
5272 pSMB->Flags = 0;
5273 pSMB->Timeout = 0;
5274 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00005275 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
5276 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07005277 offset = param_offset + params;
5278
5279 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00005280 /* BB find exact max SMB PDU from sess structure BB */
5281 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07005282 pSMB->SetupCount = 1;
5283 pSMB->Reserved3 = 0;
5284 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
5285 byte_count = 1 /* pad */ + params + 12;
5286
5287 pSMB->DataCount = cpu_to_le16(12);
5288 pSMB->ParameterCount = cpu_to_le16(params);
5289 pSMB->TotalDataCount = pSMB->DataCount;
5290 pSMB->TotalParameterCount = pSMB->ParameterCount;
5291 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5292 pSMB->DataOffset = cpu_to_le16(offset);
5293
5294 /* Params. */
5295 pSMB->FileNum = 0;
5296 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
5297
5298 /* Data. */
5299 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
5300 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
5301 pSMB->ClientUnixCap = cpu_to_le64(cap);
5302
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005303 inc_rfc1001_len(pSMB, byte_count);
Jeremy Allisonac670552005-06-22 17:26:35 -07005304 pSMB->ByteCount = cpu_to_le16(byte_count);
5305
5306 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5307 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5308 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005309 cERROR(1, "Send error in SETFSUnixInfo = %d", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07005310 } else { /* decode response */
5311 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00005312 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07005313 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07005314 }
5315 cifs_buf_release(pSMB);
5316
5317 if (rc == -EAGAIN)
5318 goto SETFSUnixRetry;
5319
5320 return rc;
5321}
5322
5323
Linus Torvalds1da177e2005-04-16 15:20:36 -07005324
5325int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005326CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon,
Steve French737b7582005-04-28 22:41:06 -07005327 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005328{
5329/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
5330 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5331 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5332 FILE_SYSTEM_POSIX_INFO *response_data;
5333 int rc = 0;
5334 int bytes_returned = 0;
5335 __u16 params, byte_count;
5336
Joe Perchesb6b38f72010-04-21 03:50:45 +00005337 cFYI(1, "In QFSPosixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005338QFSPosixRetry:
5339 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5340 (void **) &pSMBr);
5341 if (rc)
5342 return rc;
5343
5344 params = 2; /* level */
5345 pSMB->TotalDataCount = 0;
5346 pSMB->DataCount = 0;
5347 pSMB->DataOffset = 0;
5348 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005349 /* BB find exact max SMB PDU from sess structure BB */
5350 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005351 pSMB->MaxSetupCount = 0;
5352 pSMB->Reserved = 0;
5353 pSMB->Flags = 0;
5354 pSMB->Timeout = 0;
5355 pSMB->Reserved2 = 0;
5356 byte_count = params + 1 /* pad */ ;
5357 pSMB->ParameterCount = cpu_to_le16(params);
5358 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005359 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5360 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005361 pSMB->SetupCount = 1;
5362 pSMB->Reserved3 = 0;
5363 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5364 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005365 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005366 pSMB->ByteCount = cpu_to_le16(byte_count);
5367
5368 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5369 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5370 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005371 cFYI(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005372 } else { /* decode response */
5373 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5374
Jeff Layton820a8032011-05-04 08:05:26 -04005375 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005376 rc = -EIO; /* bad smb */
5377 } else {
5378 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5379 response_data =
5380 (FILE_SYSTEM_POSIX_INFO
5381 *) (((char *) &pSMBr->hdr.Protocol) +
5382 data_offset);
5383 FSData->f_bsize =
5384 le32_to_cpu(response_data->BlockSize);
5385 FSData->f_blocks =
5386 le64_to_cpu(response_data->TotalBlocks);
5387 FSData->f_bfree =
5388 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00005389 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005390 FSData->f_bavail = FSData->f_bfree;
5391 } else {
5392 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00005393 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005394 }
Steve French790fe572007-07-07 19:25:05 +00005395 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005396 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00005397 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00005398 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005399 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00005400 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005401 }
5402 }
5403 cifs_buf_release(pSMB);
5404
5405 if (rc == -EAGAIN)
5406 goto QFSPosixRetry;
5407
5408 return rc;
5409}
5410
5411
Steve French50c2f752007-07-13 00:33:32 +00005412/* We can not use write of zero bytes trick to
5413 set file size due to need for large file support. Also note that
5414 this SetPathInfo is preferred to SetFileInfo based method in next
Linus Torvalds1da177e2005-04-16 15:20:36 -07005415 routine which is only needed to work around a sharing violation bug
5416 in Samba which this routine can run into */
5417
5418int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005419CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
5420 const char *fileName, __u64 size, bool SetAllocation,
Steve French737b7582005-04-28 22:41:06 -07005421 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005422{
5423 struct smb_com_transaction2_spi_req *pSMB = NULL;
5424 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5425 struct file_end_of_file_info *parm_data;
5426 int name_len;
5427 int rc = 0;
5428 int bytes_returned = 0;
5429 __u16 params, byte_count, data_count, param_offset, offset;
5430
Joe Perchesb6b38f72010-04-21 03:50:45 +00005431 cFYI(1, "In SetEOF");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005432SetEOFRetry:
5433 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5434 (void **) &pSMBr);
5435 if (rc)
5436 return rc;
5437
5438 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5439 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005440 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5441 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005442 name_len++; /* trailing null */
5443 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005444 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005445 name_len = strnlen(fileName, PATH_MAX);
5446 name_len++; /* trailing null */
5447 strncpy(pSMB->FileName, fileName, name_len);
5448 }
5449 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005450 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005451 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07005452 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005453 pSMB->MaxSetupCount = 0;
5454 pSMB->Reserved = 0;
5455 pSMB->Flags = 0;
5456 pSMB->Timeout = 0;
5457 pSMB->Reserved2 = 0;
5458 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005459 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005460 offset = param_offset + params;
Steve French790fe572007-07-07 19:25:05 +00005461 if (SetAllocation) {
Steve French50c2f752007-07-13 00:33:32 +00005462 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5463 pSMB->InformationLevel =
5464 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5465 else
5466 pSMB->InformationLevel =
5467 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5468 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005469 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5470 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005471 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005472 else
5473 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005474 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005475 }
5476
5477 parm_data =
5478 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
5479 offset);
5480 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5481 pSMB->DataOffset = cpu_to_le16(offset);
5482 pSMB->SetupCount = 1;
5483 pSMB->Reserved3 = 0;
5484 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5485 byte_count = 3 /* pad */ + params + data_count;
5486 pSMB->DataCount = cpu_to_le16(data_count);
5487 pSMB->TotalDataCount = pSMB->DataCount;
5488 pSMB->ParameterCount = cpu_to_le16(params);
5489 pSMB->TotalParameterCount = pSMB->ParameterCount;
5490 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005491 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005492 parm_data->FileSize = cpu_to_le64(size);
5493 pSMB->ByteCount = cpu_to_le16(byte_count);
5494 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5495 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005496 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005497 cFYI(1, "SetPathInfo (file size) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005498
5499 cifs_buf_release(pSMB);
5500
5501 if (rc == -EAGAIN)
5502 goto SetEOFRetry;
5503
5504 return rc;
5505}
5506
5507int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005508CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon, __u64 size,
Steve French4b18f2a2008-04-29 00:06:05 +00005509 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005510{
5511 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005512 struct file_end_of_file_info *parm_data;
5513 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005514 __u16 params, param_offset, offset, byte_count, count;
5515
Joe Perchesb6b38f72010-04-21 03:50:45 +00005516 cFYI(1, "SetFileSize (via SetFileInfo) %lld",
5517 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07005518 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5519
Linus Torvalds1da177e2005-04-16 15:20:36 -07005520 if (rc)
5521 return rc;
5522
5523 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5524 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005525
Linus Torvalds1da177e2005-04-16 15:20:36 -07005526 params = 6;
5527 pSMB->MaxSetupCount = 0;
5528 pSMB->Reserved = 0;
5529 pSMB->Flags = 0;
5530 pSMB->Timeout = 0;
5531 pSMB->Reserved2 = 0;
5532 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5533 offset = param_offset + params;
5534
Linus Torvalds1da177e2005-04-16 15:20:36 -07005535 count = sizeof(struct file_end_of_file_info);
5536 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005537 /* BB find exact max SMB PDU from sess structure BB */
5538 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005539 pSMB->SetupCount = 1;
5540 pSMB->Reserved3 = 0;
5541 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5542 byte_count = 3 /* pad */ + params + count;
5543 pSMB->DataCount = cpu_to_le16(count);
5544 pSMB->ParameterCount = cpu_to_le16(params);
5545 pSMB->TotalDataCount = pSMB->DataCount;
5546 pSMB->TotalParameterCount = pSMB->ParameterCount;
5547 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5548 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00005549 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
5550 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005551 pSMB->DataOffset = cpu_to_le16(offset);
5552 parm_data->FileSize = cpu_to_le64(size);
5553 pSMB->Fid = fid;
Steve French790fe572007-07-07 19:25:05 +00005554 if (SetAllocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005555 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5556 pSMB->InformationLevel =
5557 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5558 else
5559 pSMB->InformationLevel =
5560 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00005561 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005562 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5563 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005564 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005565 else
5566 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005567 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005568 }
5569 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005570 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005571 pSMB->ByteCount = cpu_to_le16(byte_count);
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005572 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005573 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005574 cFYI(1, "Send error in SetFileInfo (SetFileSize) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005575 }
5576
Steve French50c2f752007-07-13 00:33:32 +00005577 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005578 since file handle passed in no longer valid */
5579
5580 return rc;
5581}
5582
Steve French50c2f752007-07-13 00:33:32 +00005583/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07005584 an open handle, rather than by pathname - this is awkward due to
5585 potential access conflicts on the open, but it is unavoidable for these
5586 old servers since the only other choice is to go from 100 nanosecond DCE
5587 time and resort to the original setpathinfo level which takes the ancient
5588 DOS time format with 2 second granularity */
5589int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005590CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005591 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005592{
5593 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005594 char *data_offset;
5595 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005596 __u16 params, param_offset, offset, byte_count, count;
5597
Joe Perchesb6b38f72010-04-21 03:50:45 +00005598 cFYI(1, "Set Times (via SetFileInfo)");
Steve Frenchcd634992005-04-28 22:41:10 -07005599 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5600
Linus Torvalds1da177e2005-04-16 15:20:36 -07005601 if (rc)
5602 return rc;
5603
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005604 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5605 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005606
Linus Torvalds1da177e2005-04-16 15:20:36 -07005607 params = 6;
5608 pSMB->MaxSetupCount = 0;
5609 pSMB->Reserved = 0;
5610 pSMB->Flags = 0;
5611 pSMB->Timeout = 0;
5612 pSMB->Reserved2 = 0;
5613 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5614 offset = param_offset + params;
5615
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005616 data_offset = (char *)pSMB +
5617 offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005618
Steve French26f57362007-08-30 22:09:15 +00005619 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005620 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005621 /* BB find max SMB PDU from sess */
5622 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005623 pSMB->SetupCount = 1;
5624 pSMB->Reserved3 = 0;
5625 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5626 byte_count = 3 /* pad */ + params + count;
5627 pSMB->DataCount = cpu_to_le16(count);
5628 pSMB->ParameterCount = cpu_to_le16(params);
5629 pSMB->TotalDataCount = pSMB->DataCount;
5630 pSMB->TotalParameterCount = pSMB->ParameterCount;
5631 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5632 pSMB->DataOffset = cpu_to_le16(offset);
5633 pSMB->Fid = fid;
5634 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5635 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5636 else
5637 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5638 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005639 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005640 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005641 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005642 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005643 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005644 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005645
Steve French50c2f752007-07-13 00:33:32 +00005646 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005647 since file handle passed in no longer valid */
5648
5649 return rc;
5650}
5651
Jeff Layton6d22f092008-09-23 11:48:35 -04005652int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005653CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6d22f092008-09-23 11:48:35 -04005654 bool delete_file, __u16 fid, __u32 pid_of_opener)
5655{
5656 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5657 char *data_offset;
5658 int rc = 0;
5659 __u16 params, param_offset, offset, byte_count, count;
5660
Joe Perchesb6b38f72010-04-21 03:50:45 +00005661 cFYI(1, "Set File Disposition (via SetFileInfo)");
Jeff Layton6d22f092008-09-23 11:48:35 -04005662 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5663
5664 if (rc)
5665 return rc;
5666
5667 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5668 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5669
5670 params = 6;
5671 pSMB->MaxSetupCount = 0;
5672 pSMB->Reserved = 0;
5673 pSMB->Flags = 0;
5674 pSMB->Timeout = 0;
5675 pSMB->Reserved2 = 0;
5676 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5677 offset = param_offset + params;
5678
5679 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5680
5681 count = 1;
5682 pSMB->MaxParameterCount = cpu_to_le16(2);
5683 /* BB find max SMB PDU from sess */
5684 pSMB->MaxDataCount = cpu_to_le16(1000);
5685 pSMB->SetupCount = 1;
5686 pSMB->Reserved3 = 0;
5687 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5688 byte_count = 3 /* pad */ + params + count;
5689 pSMB->DataCount = cpu_to_le16(count);
5690 pSMB->ParameterCount = cpu_to_le16(params);
5691 pSMB->TotalDataCount = pSMB->DataCount;
5692 pSMB->TotalParameterCount = pSMB->ParameterCount;
5693 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5694 pSMB->DataOffset = cpu_to_le16(offset);
5695 pSMB->Fid = fid;
5696 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5697 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005698 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton6d22f092008-09-23 11:48:35 -04005699 pSMB->ByteCount = cpu_to_le16(byte_count);
5700 *data_offset = delete_file ? 1 : 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005701 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Jeff Layton6d22f092008-09-23 11:48:35 -04005702 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005703 cFYI(1, "Send error in SetFileDisposition = %d", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005704
5705 return rc;
5706}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005707
5708int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005709CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6fc000e2008-08-02 07:26:12 -04005710 const char *fileName, const FILE_BASIC_INFO *data,
5711 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005712{
5713 TRANSACTION2_SPI_REQ *pSMB = NULL;
5714 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5715 int name_len;
5716 int rc = 0;
5717 int bytes_returned = 0;
5718 char *data_offset;
5719 __u16 params, param_offset, offset, byte_count, count;
5720
Joe Perchesb6b38f72010-04-21 03:50:45 +00005721 cFYI(1, "In SetTimes");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005722
5723SetTimesRetry:
5724 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5725 (void **) &pSMBr);
5726 if (rc)
5727 return rc;
5728
5729 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5730 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005731 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5732 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005733 name_len++; /* trailing null */
5734 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005735 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005736 name_len = strnlen(fileName, PATH_MAX);
5737 name_len++; /* trailing null */
5738 strncpy(pSMB->FileName, fileName, name_len);
5739 }
5740
5741 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005742 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005743 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005744 /* BB find max SMB PDU from sess structure BB */
5745 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005746 pSMB->MaxSetupCount = 0;
5747 pSMB->Reserved = 0;
5748 pSMB->Flags = 0;
5749 pSMB->Timeout = 0;
5750 pSMB->Reserved2 = 0;
5751 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005752 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005753 offset = param_offset + params;
5754 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5755 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5756 pSMB->DataOffset = cpu_to_le16(offset);
5757 pSMB->SetupCount = 1;
5758 pSMB->Reserved3 = 0;
5759 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5760 byte_count = 3 /* pad */ + params + count;
5761
5762 pSMB->DataCount = cpu_to_le16(count);
5763 pSMB->ParameterCount = cpu_to_le16(params);
5764 pSMB->TotalDataCount = pSMB->DataCount;
5765 pSMB->TotalParameterCount = pSMB->ParameterCount;
5766 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5767 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5768 else
5769 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5770 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005771 inc_rfc1001_len(pSMB, byte_count);
Steve French26f57362007-08-30 22:09:15 +00005772 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005773 pSMB->ByteCount = cpu_to_le16(byte_count);
5774 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5775 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005776 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005777 cFYI(1, "SetPathInfo (times) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005778
5779 cifs_buf_release(pSMB);
5780
5781 if (rc == -EAGAIN)
5782 goto SetTimesRetry;
5783
5784 return rc;
5785}
5786
5787/* Can not be used to set time stamps yet (due to old DOS time format) */
5788/* Can be used to set attributes */
5789#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5790 handling it anyway and NT4 was what we thought it would be needed for
5791 Do not delete it until we prove whether needed for Win9x though */
5792int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005793CIFSSMBSetAttrLegacy(unsigned int xid, struct cifs_tcon *tcon, char *fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005794 __u16 dos_attrs, const struct nls_table *nls_codepage)
5795{
5796 SETATTR_REQ *pSMB = NULL;
5797 SETATTR_RSP *pSMBr = NULL;
5798 int rc = 0;
5799 int bytes_returned;
5800 int name_len;
5801
Joe Perchesb6b38f72010-04-21 03:50:45 +00005802 cFYI(1, "In SetAttrLegacy");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005803
5804SetAttrLgcyRetry:
5805 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5806 (void **) &pSMBr);
5807 if (rc)
5808 return rc;
5809
5810 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5811 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005812 ConvertToUTF16((__le16 *) pSMB->fileName, fileName,
5813 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005814 name_len++; /* trailing null */
5815 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005816 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005817 name_len = strnlen(fileName, PATH_MAX);
5818 name_len++; /* trailing null */
5819 strncpy(pSMB->fileName, fileName, name_len);
5820 }
5821 pSMB->attr = cpu_to_le16(dos_attrs);
5822 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005823 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005824 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5825 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5826 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005827 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005828 cFYI(1, "Error in LegacySetAttr = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005829
5830 cifs_buf_release(pSMB);
5831
5832 if (rc == -EAGAIN)
5833 goto SetAttrLgcyRetry;
5834
5835 return rc;
5836}
5837#endif /* temporarily unneeded SetAttr legacy function */
5838
Jeff Layton654cf142009-07-09 20:02:49 -04005839static void
5840cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5841 const struct cifs_unix_set_info_args *args)
5842{
5843 u64 mode = args->mode;
5844
5845 /*
5846 * Samba server ignores set of file size to zero due to bugs in some
5847 * older clients, but we should be precise - we use SetFileSize to
5848 * set file size and do not want to truncate file size to zero
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005849 * accidentally as happened on one Samba server beta by putting
Jeff Layton654cf142009-07-09 20:02:49 -04005850 * zero instead of -1 here
5851 */
5852 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5853 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5854 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5855 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5856 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5857 data_offset->Uid = cpu_to_le64(args->uid);
5858 data_offset->Gid = cpu_to_le64(args->gid);
5859 /* better to leave device as zero when it is */
5860 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5861 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5862 data_offset->Permissions = cpu_to_le64(mode);
5863
5864 if (S_ISREG(mode))
5865 data_offset->Type = cpu_to_le32(UNIX_FILE);
5866 else if (S_ISDIR(mode))
5867 data_offset->Type = cpu_to_le32(UNIX_DIR);
5868 else if (S_ISLNK(mode))
5869 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5870 else if (S_ISCHR(mode))
5871 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5872 else if (S_ISBLK(mode))
5873 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5874 else if (S_ISFIFO(mode))
5875 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5876 else if (S_ISSOCK(mode))
5877 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5878}
5879
Linus Torvalds1da177e2005-04-16 15:20:36 -07005880int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005881CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005882 const struct cifs_unix_set_info_args *args,
5883 u16 fid, u32 pid_of_opener)
5884{
5885 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005886 char *data_offset;
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005887 int rc = 0;
5888 u16 params, param_offset, offset, byte_count, count;
5889
Joe Perchesb6b38f72010-04-21 03:50:45 +00005890 cFYI(1, "Set Unix Info (via SetFileInfo)");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005891 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5892
5893 if (rc)
5894 return rc;
5895
5896 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5897 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5898
5899 params = 6;
5900 pSMB->MaxSetupCount = 0;
5901 pSMB->Reserved = 0;
5902 pSMB->Flags = 0;
5903 pSMB->Timeout = 0;
5904 pSMB->Reserved2 = 0;
5905 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5906 offset = param_offset + params;
5907
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005908 data_offset = (char *)pSMB +
5909 offsetof(struct smb_hdr, Protocol) + offset;
5910
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005911 count = sizeof(FILE_UNIX_BASIC_INFO);
5912
5913 pSMB->MaxParameterCount = cpu_to_le16(2);
5914 /* BB find max SMB PDU from sess */
5915 pSMB->MaxDataCount = cpu_to_le16(1000);
5916 pSMB->SetupCount = 1;
5917 pSMB->Reserved3 = 0;
5918 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5919 byte_count = 3 /* pad */ + params + count;
5920 pSMB->DataCount = cpu_to_le16(count);
5921 pSMB->ParameterCount = cpu_to_le16(params);
5922 pSMB->TotalDataCount = pSMB->DataCount;
5923 pSMB->TotalParameterCount = pSMB->ParameterCount;
5924 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5925 pSMB->DataOffset = cpu_to_le16(offset);
5926 pSMB->Fid = fid;
5927 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5928 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005929 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005930 pSMB->ByteCount = cpu_to_le16(byte_count);
5931
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005932 cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005933
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005934 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005935 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005936 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005937
5938 /* Note: On -EAGAIN error only caller can retry on handle based calls
5939 since file handle passed in no longer valid */
5940
5941 return rc;
5942}
5943
5944int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005945CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005946 const char *file_name,
Jeff Layton01ea95e2009-07-09 20:02:49 -04005947 const struct cifs_unix_set_info_args *args,
5948 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005949{
5950 TRANSACTION2_SPI_REQ *pSMB = NULL;
5951 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5952 int name_len;
5953 int rc = 0;
5954 int bytes_returned = 0;
5955 FILE_UNIX_BASIC_INFO *data_offset;
5956 __u16 params, param_offset, offset, count, byte_count;
5957
Joe Perchesb6b38f72010-04-21 03:50:45 +00005958 cFYI(1, "In SetUID/GID/Mode");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005959setPermsRetry:
5960 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5961 (void **) &pSMBr);
5962 if (rc)
5963 return rc;
5964
5965 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5966 name_len =
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005967 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06005968 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005969 name_len++; /* trailing null */
5970 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005971 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005972 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005973 name_len++; /* trailing null */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005974 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005975 }
5976
5977 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005978 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005979 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005980 /* BB find max SMB PDU from sess structure BB */
5981 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005982 pSMB->MaxSetupCount = 0;
5983 pSMB->Reserved = 0;
5984 pSMB->Flags = 0;
5985 pSMB->Timeout = 0;
5986 pSMB->Reserved2 = 0;
5987 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005988 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005989 offset = param_offset + params;
5990 data_offset =
5991 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5992 offset);
5993 memset(data_offset, 0, count);
5994 pSMB->DataOffset = cpu_to_le16(offset);
5995 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5996 pSMB->SetupCount = 1;
5997 pSMB->Reserved3 = 0;
5998 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5999 byte_count = 3 /* pad */ + params + count;
6000 pSMB->ParameterCount = cpu_to_le16(params);
6001 pSMB->DataCount = cpu_to_le16(count);
6002 pSMB->TotalParameterCount = pSMB->ParameterCount;
6003 pSMB->TotalDataCount = pSMB->DataCount;
6004 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6005 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006006 inc_rfc1001_len(pSMB, byte_count);
Steve French50c2f752007-07-13 00:33:32 +00006007
Jeff Layton654cf142009-07-09 20:02:49 -04006008 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006009
6010 pSMB->ByteCount = cpu_to_le16(byte_count);
6011 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6012 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006013 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00006014 cFYI(1, "SetPathInfo (perms) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006015
Steve French0d817bc2008-05-22 02:02:03 +00006016 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006017 if (rc == -EAGAIN)
6018 goto setPermsRetry;
6019 return rc;
6020}
6021
Linus Torvalds1da177e2005-04-16 15:20:36 -07006022#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05006023/*
6024 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
6025 * function used by listxattr and getxattr type calls. When ea_name is set,
6026 * it looks for that attribute name and stuffs that value into the EAData
6027 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
6028 * buffer. In both cases, the return value is either the length of the
6029 * resulting data or a negative error code. If EAData is a NULL pointer then
6030 * the data isn't copied to it, but the length is returned.
6031 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006032ssize_t
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006033CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05006034 const unsigned char *searchName, const unsigned char *ea_name,
6035 char *EAData, size_t buf_size,
6036 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006037{
6038 /* BB assumes one setup word */
6039 TRANSACTION2_QPI_REQ *pSMB = NULL;
6040 TRANSACTION2_QPI_RSP *pSMBr = NULL;
6041 int rc = 0;
6042 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05006043 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006044 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00006045 struct fea *temp_fea;
6046 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006047 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006048 __u16 params, byte_count, data_offset;
Jeff Layton5980fc92011-07-28 12:48:26 -04006049 unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006050
Joe Perchesb6b38f72010-04-21 03:50:45 +00006051 cFYI(1, "In Query All EAs path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006052QAllEAsRetry:
6053 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6054 (void **) &pSMBr);
6055 if (rc)
6056 return rc;
6057
6058 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05006059 list_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006060 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
6061 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05006062 list_len++; /* trailing null */
6063 list_len *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006064 } else { /* BB improve the check for buffer overruns BB */
Jeff Layton6e462b92010-02-10 16:18:26 -05006065 list_len = strnlen(searchName, PATH_MAX);
6066 list_len++; /* trailing null */
6067 strncpy(pSMB->FileName, searchName, list_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006068 }
6069
Jeff Layton6e462b92010-02-10 16:18:26 -05006070 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006071 pSMB->TotalDataCount = 0;
6072 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006073 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05006074 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006075 pSMB->MaxSetupCount = 0;
6076 pSMB->Reserved = 0;
6077 pSMB->Flags = 0;
6078 pSMB->Timeout = 0;
6079 pSMB->Reserved2 = 0;
6080 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00006081 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006082 pSMB->DataCount = 0;
6083 pSMB->DataOffset = 0;
6084 pSMB->SetupCount = 1;
6085 pSMB->Reserved3 = 0;
6086 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
6087 byte_count = params + 1 /* pad */ ;
6088 pSMB->TotalParameterCount = cpu_to_le16(params);
6089 pSMB->ParameterCount = pSMB->TotalParameterCount;
6090 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
6091 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006092 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006093 pSMB->ByteCount = cpu_to_le16(byte_count);
6094
6095 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6096 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6097 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006098 cFYI(1, "Send error in QueryAllEAs = %d", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05006099 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006100 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006101
6102
6103 /* BB also check enough total bytes returned */
6104 /* BB we need to improve the validity checking
6105 of these trans2 responses */
6106
6107 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Jeff Layton820a8032011-05-04 08:05:26 -04006108 if (rc || get_bcc(&pSMBr->hdr) < 4) {
Jeff Laytonf0d38682010-02-10 16:18:26 -05006109 rc = -EIO; /* bad smb */
6110 goto QAllEAsOut;
6111 }
6112
6113 /* check that length of list is not more than bcc */
6114 /* check that each entry does not go beyond length
6115 of list */
6116 /* check that each element of each entry does not
6117 go beyond end of list */
6118 /* validate_trans2_offsets() */
6119 /* BB check if start of smb + data_offset > &bcc+ bcc */
6120
6121 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
6122 ea_response_data = (struct fealist *)
6123 (((char *) &pSMBr->hdr.Protocol) + data_offset);
6124
Jeff Layton6e462b92010-02-10 16:18:26 -05006125 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesb6b38f72010-04-21 03:50:45 +00006126 cFYI(1, "ea length %d", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05006127 if (list_len <= 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006128 cFYI(1, "empty EA list returned from server");
Jeff Laytonf0d38682010-02-10 16:18:26 -05006129 goto QAllEAsOut;
6130 }
6131
Jeff Layton0cd126b2010-02-10 16:18:26 -05006132 /* make sure list_len doesn't go past end of SMB */
Jeff Layton690c5222011-01-20 13:36:51 -05006133 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
Jeff Layton0cd126b2010-02-10 16:18:26 -05006134 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006135 cFYI(1, "EA list appears to go beyond SMB");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006136 rc = -EIO;
6137 goto QAllEAsOut;
6138 }
6139
Jeff Laytonf0d38682010-02-10 16:18:26 -05006140 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05006141 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006142 temp_fea = ea_response_data->list;
6143 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05006144 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00006145 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006146 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006147
Jeff Layton6e462b92010-02-10 16:18:26 -05006148 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006149 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006150 /* make sure we can read name_len and value_len */
6151 if (list_len < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006152 cFYI(1, "EA entry goes beyond length of list");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006153 rc = -EIO;
6154 goto QAllEAsOut;
6155 }
6156
6157 name_len = temp_fea->name_len;
6158 value_len = le16_to_cpu(temp_fea->value_len);
6159 list_len -= name_len + 1 + value_len;
6160 if (list_len < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006161 cFYI(1, "EA entry goes beyond length of list");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006162 rc = -EIO;
6163 goto QAllEAsOut;
6164 }
6165
Jeff Layton31c05192010-02-10 16:18:26 -05006166 if (ea_name) {
Jeff Layton91d065c2011-07-26 18:23:47 -04006167 if (ea_name_len == name_len &&
Jeff Laytonac423442011-10-11 06:41:32 -04006168 memcmp(ea_name, temp_ptr, name_len) == 0) {
Jeff Layton31c05192010-02-10 16:18:26 -05006169 temp_ptr += name_len + 1;
6170 rc = value_len;
6171 if (buf_size == 0)
6172 goto QAllEAsOut;
6173 if ((size_t)value_len > buf_size) {
6174 rc = -ERANGE;
6175 goto QAllEAsOut;
6176 }
6177 memcpy(EAData, temp_ptr, value_len);
6178 goto QAllEAsOut;
6179 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006180 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05006181 /* account for prefix user. and trailing null */
6182 rc += (5 + 1 + name_len);
6183 if (rc < (int) buf_size) {
6184 memcpy(EAData, "user.", 5);
6185 EAData += 5;
6186 memcpy(EAData, temp_ptr, name_len);
6187 EAData += name_len;
6188 /* null terminate name */
6189 *EAData = 0;
6190 ++EAData;
6191 } else if (buf_size == 0) {
6192 /* skip copy - calc size only */
6193 } else {
6194 /* stop before overrun buffer */
6195 rc = -ERANGE;
6196 break;
6197 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006198 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05006199 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006200 temp_fea = (struct fea *)temp_ptr;
6201 }
6202
Jeff Layton31c05192010-02-10 16:18:26 -05006203 /* didn't find the named attribute */
6204 if (ea_name)
6205 rc = -ENODATA;
6206
Jeff Laytonf0d38682010-02-10 16:18:26 -05006207QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00006208 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006209 if (rc == -EAGAIN)
6210 goto QAllEAsRetry;
6211
6212 return (ssize_t)rc;
6213}
6214
Linus Torvalds1da177e2005-04-16 15:20:36 -07006215int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006216CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
6217 const char *fileName, const char *ea_name, const void *ea_value,
Steve French50c2f752007-07-13 00:33:32 +00006218 const __u16 ea_value_len, const struct nls_table *nls_codepage,
6219 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006220{
6221 struct smb_com_transaction2_spi_req *pSMB = NULL;
6222 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
6223 struct fealist *parm_data;
6224 int name_len;
6225 int rc = 0;
6226 int bytes_returned = 0;
6227 __u16 params, param_offset, byte_count, offset, count;
6228
Joe Perchesb6b38f72010-04-21 03:50:45 +00006229 cFYI(1, "In SetEA");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006230SetEARetry:
6231 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6232 (void **) &pSMBr);
6233 if (rc)
6234 return rc;
6235
6236 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6237 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006238 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
6239 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006240 name_len++; /* trailing null */
6241 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00006242 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006243 name_len = strnlen(fileName, PATH_MAX);
6244 name_len++; /* trailing null */
6245 strncpy(pSMB->FileName, fileName, name_len);
6246 }
6247
6248 params = 6 + name_len;
6249
6250 /* done calculating parms using name_len of file name,
6251 now use name_len to calculate length of ea name
6252 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00006253 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006254 name_len = 0;
6255 else
Steve French50c2f752007-07-13 00:33:32 +00006256 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006257
Steve Frenchdae5dbd2007-12-30 23:49:57 +00006258 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006259 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006260 /* BB find max SMB PDU from sess */
6261 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006262 pSMB->MaxSetupCount = 0;
6263 pSMB->Reserved = 0;
6264 pSMB->Flags = 0;
6265 pSMB->Timeout = 0;
6266 pSMB->Reserved2 = 0;
6267 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006268 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006269 offset = param_offset + params;
6270 pSMB->InformationLevel =
6271 cpu_to_le16(SMB_SET_FILE_EA);
6272
6273 parm_data =
6274 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
6275 offset);
6276 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6277 pSMB->DataOffset = cpu_to_le16(offset);
6278 pSMB->SetupCount = 1;
6279 pSMB->Reserved3 = 0;
6280 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6281 byte_count = 3 /* pad */ + params + count;
6282 pSMB->DataCount = cpu_to_le16(count);
6283 parm_data->list_len = cpu_to_le32(count);
6284 parm_data->list[0].EA_flags = 0;
6285 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08006286 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006287 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00006288 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00006289 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006290 parm_data->list[0].name[name_len] = 0;
6291 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
6292 /* caller ensures that ea_value_len is less than 64K but
6293 we need to ensure that it fits within the smb */
6294
Steve French50c2f752007-07-13 00:33:32 +00006295 /*BB add length check to see if it would fit in
6296 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00006297 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
6298 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00006299 memcpy(parm_data->list[0].name+name_len+1,
6300 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006301
6302 pSMB->TotalDataCount = pSMB->DataCount;
6303 pSMB->ParameterCount = cpu_to_le16(params);
6304 pSMB->TotalParameterCount = pSMB->ParameterCount;
6305 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006306 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006307 pSMB->ByteCount = cpu_to_le16(byte_count);
6308 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6309 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006310 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00006311 cFYI(1, "SetPathInfo (EA) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006312
6313 cifs_buf_release(pSMB);
6314
6315 if (rc == -EAGAIN)
6316 goto SetEARetry;
6317
6318 return rc;
6319}
Linus Torvalds1da177e2005-04-16 15:20:36 -07006320#endif
Steve French0eff0e22011-02-24 05:39:23 +00006321
6322#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */
6323/*
6324 * Years ago the kernel added a "dnotify" function for Samba server,
6325 * to allow network clients (such as Windows) to display updated
6326 * lists of files in directory listings automatically when
6327 * files are added by one user when another user has the
6328 * same directory open on their desktop. The Linux cifs kernel
6329 * client hooked into the kernel side of this interface for
6330 * the same reason, but ironically when the VFS moved from
6331 * "dnotify" to "inotify" it became harder to plug in Linux
6332 * network file system clients (the most obvious use case
6333 * for notify interfaces is when multiple users can update
6334 * the contents of the same directory - exactly what network
6335 * file systems can do) although the server (Samba) could
6336 * still use it. For the short term we leave the worker
6337 * function ifdeffed out (below) until inotify is fixed
6338 * in the VFS to make it easier to plug in network file
6339 * system clients. If inotify turns out to be permanently
6340 * incompatible for network fs clients, we could instead simply
6341 * expose this config flag by adding a future cifs (and smb2) notify ioctl.
6342 */
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006343int CIFSSMBNotify(const unsigned int xid, struct cifs_tcon *tcon,
Steve French0eff0e22011-02-24 05:39:23 +00006344 const int notify_subdirs, const __u16 netfid,
6345 __u32 filter, struct file *pfile, int multishot,
6346 const struct nls_table *nls_codepage)
6347{
6348 int rc = 0;
6349 struct smb_com_transaction_change_notify_req *pSMB = NULL;
6350 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
6351 struct dir_notify_req *dnotify_req;
6352 int bytes_returned;
6353
6354 cFYI(1, "In CIFSSMBNotify for file handle %d", (int)netfid);
6355 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
6356 (void **) &pSMBr);
6357 if (rc)
6358 return rc;
6359
6360 pSMB->TotalParameterCount = 0 ;
6361 pSMB->TotalDataCount = 0;
6362 pSMB->MaxParameterCount = cpu_to_le32(2);
Jeff Laytonc974bef2011-10-11 06:41:32 -04006363 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Steve French0eff0e22011-02-24 05:39:23 +00006364 pSMB->MaxSetupCount = 4;
6365 pSMB->Reserved = 0;
6366 pSMB->ParameterOffset = 0;
6367 pSMB->DataCount = 0;
6368 pSMB->DataOffset = 0;
6369 pSMB->SetupCount = 4; /* single byte does not need le conversion */
6370 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
6371 pSMB->ParameterCount = pSMB->TotalParameterCount;
6372 if (notify_subdirs)
6373 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
6374 pSMB->Reserved2 = 0;
6375 pSMB->CompletionFilter = cpu_to_le32(filter);
6376 pSMB->Fid = netfid; /* file handle always le */
6377 pSMB->ByteCount = 0;
6378
6379 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6380 (struct smb_hdr *)pSMBr, &bytes_returned,
6381 CIFS_ASYNC_OP);
6382 if (rc) {
6383 cFYI(1, "Error in Notify = %d", rc);
6384 } else {
6385 /* Add file to outstanding requests */
6386 /* BB change to kmem cache alloc */
6387 dnotify_req = kmalloc(
6388 sizeof(struct dir_notify_req),
6389 GFP_KERNEL);
6390 if (dnotify_req) {
6391 dnotify_req->Pid = pSMB->hdr.Pid;
6392 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
6393 dnotify_req->Mid = pSMB->hdr.Mid;
6394 dnotify_req->Tid = pSMB->hdr.Tid;
6395 dnotify_req->Uid = pSMB->hdr.Uid;
6396 dnotify_req->netfid = netfid;
6397 dnotify_req->pfile = pfile;
6398 dnotify_req->filter = filter;
6399 dnotify_req->multishot = multishot;
6400 spin_lock(&GlobalMid_Lock);
6401 list_add_tail(&dnotify_req->lhead,
6402 &GlobalDnotifyReqList);
6403 spin_unlock(&GlobalMid_Lock);
6404 } else
6405 rc = -ENOMEM;
6406 }
6407 cifs_buf_release(pSMB);
6408 return rc;
6409}
6410#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */