blob: 2a9b2738770875597c14041154e2b7bcb964359d [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 Shilovskyed6875e2012-09-18 16:20:25 -0700905CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
906 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907{
908 DELETE_FILE_REQ *pSMB = NULL;
909 DELETE_FILE_RSP *pSMBr = NULL;
910 int rc = 0;
911 int bytes_returned;
912 int name_len;
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700913 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914
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) {
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700922 name_len = cifsConvertToUTF16((__le16 *) pSMB->fileName, name,
923 PATH_MAX, cifs_sb->local_nls,
924 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 */
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700928 name_len = strnlen(name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929 name_len++; /* trailing null */
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700930 strncpy(pSMB->fileName, name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931 }
932 pSMB->SearchAttributes =
933 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
934 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000935 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936 pSMB->ByteCount = cpu_to_le16(name_len + 1);
937 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
938 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400939 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000940 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000941 cFYI(1, "Error in RMFile = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942
943 cifs_buf_release(pSMB);
944 if (rc == -EAGAIN)
945 goto DelFileRetry;
946
947 return rc;
948}
949
950int
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400951CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
952 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953{
954 DELETE_DIRECTORY_REQ *pSMB = NULL;
955 DELETE_DIRECTORY_RSP *pSMBr = NULL;
956 int rc = 0;
957 int bytes_returned;
958 int name_len;
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400959 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960
Joe Perchesb6b38f72010-04-21 03:50:45 +0000961 cFYI(1, "In CIFSSMBRmDir");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962RmDirRetry:
963 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
964 (void **) &pSMBr);
965 if (rc)
966 return rc;
967
968 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400969 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
970 PATH_MAX, cifs_sb->local_nls,
971 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972 name_len++; /* trailing null */
973 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700974 } else { /* BB improve check for buffer overruns BB */
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400975 name_len = strnlen(name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 name_len++; /* trailing null */
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400977 strncpy(pSMB->DirName, name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 }
979
980 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000981 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 pSMB->ByteCount = cpu_to_le16(name_len + 1);
983 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
984 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400985 cifs_stats_inc(&tcon->stats.cifs_stats.num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000986 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000987 cFYI(1, "Error in RMDir = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988
989 cifs_buf_release(pSMB);
990 if (rc == -EAGAIN)
991 goto RmDirRetry;
992 return rc;
993}
994
995int
Pavel Shilovskyf4367202012-03-17 11:41:12 +0300996CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
997 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998{
999 int rc = 0;
1000 CREATE_DIRECTORY_REQ *pSMB = NULL;
1001 CREATE_DIRECTORY_RSP *pSMBr = NULL;
1002 int bytes_returned;
1003 int name_len;
Pavel Shilovskyf4367202012-03-17 11:41:12 +03001004 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005
Joe Perchesb6b38f72010-04-21 03:50:45 +00001006 cFYI(1, "In CIFSSMBMkDir");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007MkDirRetry:
1008 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
1009 (void **) &pSMBr);
1010 if (rc)
1011 return rc;
1012
1013 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06001014 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
Pavel Shilovskyf4367202012-03-17 11:41:12 +03001015 PATH_MAX, cifs_sb->local_nls,
1016 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 name_len++; /* trailing null */
1018 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -07001019 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 name_len = strnlen(name, PATH_MAX);
1021 name_len++; /* trailing null */
1022 strncpy(pSMB->DirName, name, name_len);
1023 }
1024
1025 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001026 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027 pSMB->ByteCount = cpu_to_le16(name_len + 1);
1028 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1029 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001030 cifs_stats_inc(&tcon->stats.cifs_stats.num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +00001031 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001032 cFYI(1, "Error in Mkdir = %d", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07001033
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034 cifs_buf_release(pSMB);
1035 if (rc == -EAGAIN)
1036 goto MkDirRetry;
1037 return rc;
1038}
1039
Steve French2dd29d32007-04-23 22:07:35 +00001040int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001041CIFSPOSIXCreate(const unsigned int xid, struct cifs_tcon *tcon,
1042 __u32 posix_flags, __u64 mode, __u16 *netfid,
1043 FILE_UNIX_BASIC_INFO *pRetData, __u32 *pOplock,
1044 const char *name, const struct nls_table *nls_codepage,
1045 int remap)
Steve French2dd29d32007-04-23 22:07:35 +00001046{
1047 TRANSACTION2_SPI_REQ *pSMB = NULL;
1048 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1049 int name_len;
1050 int rc = 0;
1051 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001052 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +00001053 OPEN_PSX_REQ *pdata;
1054 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +00001055
Joe Perchesb6b38f72010-04-21 03:50:45 +00001056 cFYI(1, "In POSIX Create");
Steve French2dd29d32007-04-23 22:07:35 +00001057PsxCreat:
1058 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1059 (void **) &pSMBr);
1060 if (rc)
1061 return rc;
1062
1063 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1064 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001065 cifsConvertToUTF16((__le16 *) pSMB->FileName, name,
1066 PATH_MAX, nls_codepage, remap);
Steve French2dd29d32007-04-23 22:07:35 +00001067 name_len++; /* trailing null */
1068 name_len *= 2;
1069 } else { /* BB improve the check for buffer overruns BB */
1070 name_len = strnlen(name, PATH_MAX);
1071 name_len++; /* trailing null */
1072 strncpy(pSMB->FileName, name, name_len);
1073 }
1074
1075 params = 6 + name_len;
1076 count = sizeof(OPEN_PSX_REQ);
1077 pSMB->MaxParameterCount = cpu_to_le16(2);
1078 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1079 pSMB->MaxSetupCount = 0;
1080 pSMB->Reserved = 0;
1081 pSMB->Flags = 0;
1082 pSMB->Timeout = 0;
1083 pSMB->Reserved2 = 0;
1084 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001085 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001086 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001087 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001088 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001089 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001090 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001091 pdata->OpenFlags = cpu_to_le32(*pOplock);
1092 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1093 pSMB->DataOffset = cpu_to_le16(offset);
1094 pSMB->SetupCount = 1;
1095 pSMB->Reserved3 = 0;
1096 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1097 byte_count = 3 /* pad */ + params + count;
1098
1099 pSMB->DataCount = cpu_to_le16(count);
1100 pSMB->ParameterCount = cpu_to_le16(params);
1101 pSMB->TotalDataCount = pSMB->DataCount;
1102 pSMB->TotalParameterCount = pSMB->ParameterCount;
1103 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1104 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001105 inc_rfc1001_len(pSMB, byte_count);
Steve French2dd29d32007-04-23 22:07:35 +00001106 pSMB->ByteCount = cpu_to_le16(byte_count);
1107 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1108 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1109 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001110 cFYI(1, "Posix create returned %d", rc);
Steve French2dd29d32007-04-23 22:07:35 +00001111 goto psx_create_err;
1112 }
1113
Joe Perchesb6b38f72010-04-21 03:50:45 +00001114 cFYI(1, "copying inode info");
Steve French2dd29d32007-04-23 22:07:35 +00001115 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1116
Jeff Layton820a8032011-05-04 08:05:26 -04001117 if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) {
Steve French2dd29d32007-04-23 22:07:35 +00001118 rc = -EIO; /* bad smb */
1119 goto psx_create_err;
1120 }
1121
1122 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001123 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001124 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001125
Steve French2dd29d32007-04-23 22:07:35 +00001126 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001127 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001128 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1129 /* Let caller know file was created so we can set the mode. */
1130 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001131 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001132 *pOplock |= CIFS_CREATE_ACTION;
1133 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001134 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1135 pRetData->Type = cpu_to_le32(-1); /* unknown */
Joe Perchesb6b38f72010-04-21 03:50:45 +00001136 cFYI(DBG2, "unknown type");
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001137 } else {
Jeff Layton820a8032011-05-04 08:05:26 -04001138 if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001139 + sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001140 cERROR(1, "Open response data too small");
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001141 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001142 goto psx_create_err;
1143 }
Steve French50c2f752007-07-13 00:33:32 +00001144 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001145 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001146 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001147 }
Steve French2dd29d32007-04-23 22:07:35 +00001148
1149psx_create_err:
1150 cifs_buf_release(pSMB);
1151
Steve French65bc98b2009-07-10 15:27:25 +00001152 if (posix_flags & SMB_O_DIRECTORY)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001153 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixmkdirs);
Steve French65bc98b2009-07-10 15:27:25 +00001154 else
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001155 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixopens);
Steve French2dd29d32007-04-23 22:07:35 +00001156
1157 if (rc == -EAGAIN)
1158 goto PsxCreat;
1159
Steve French50c2f752007-07-13 00:33:32 +00001160 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001161}
1162
Steve Frencha9d02ad2005-08-24 23:06:05 -07001163static __u16 convert_disposition(int disposition)
1164{
1165 __u16 ofun = 0;
1166
1167 switch (disposition) {
1168 case FILE_SUPERSEDE:
1169 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1170 break;
1171 case FILE_OPEN:
1172 ofun = SMBOPEN_OAPPEND;
1173 break;
1174 case FILE_CREATE:
1175 ofun = SMBOPEN_OCREATE;
1176 break;
1177 case FILE_OPEN_IF:
1178 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1179 break;
1180 case FILE_OVERWRITE:
1181 ofun = SMBOPEN_OTRUNC;
1182 break;
1183 case FILE_OVERWRITE_IF:
1184 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1185 break;
1186 default:
Joe Perchesb6b38f72010-04-21 03:50:45 +00001187 cFYI(1, "unknown disposition %d", disposition);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001188 ofun = SMBOPEN_OAPPEND; /* regular open */
1189 }
1190 return ofun;
1191}
1192
Jeff Layton35fc37d2008-05-14 10:22:03 -07001193static int
1194access_flags_to_smbopen_mode(const int access_flags)
1195{
1196 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1197
1198 if (masked_flags == GENERIC_READ)
1199 return SMBOPEN_READ;
1200 else if (masked_flags == GENERIC_WRITE)
1201 return SMBOPEN_WRITE;
1202
1203 /* just go for read/write */
1204 return SMBOPEN_READWRITE;
1205}
1206
Steve Frencha9d02ad2005-08-24 23:06:05 -07001207int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001208SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001209 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001210 const int access_flags, const int create_options, __u16 *netfid,
1211 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001212 const struct nls_table *nls_codepage, int remap)
1213{
1214 int rc = -EACCES;
1215 OPENX_REQ *pSMB = NULL;
1216 OPENX_RSP *pSMBr = NULL;
1217 int bytes_returned;
1218 int name_len;
1219 __u16 count;
1220
1221OldOpenRetry:
1222 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1223 (void **) &pSMBr);
1224 if (rc)
1225 return rc;
1226
1227 pSMB->AndXCommand = 0xFF; /* none */
1228
1229 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1230 count = 1; /* account for one byte pad to word boundary */
1231 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001232 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1233 fileName, PATH_MAX, nls_codepage, remap);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001234 name_len++; /* trailing null */
1235 name_len *= 2;
1236 } else { /* BB improve check for buffer overruns BB */
1237 count = 0; /* no pad */
1238 name_len = strnlen(fileName, PATH_MAX);
1239 name_len++; /* trailing null */
1240 strncpy(pSMB->fileName, fileName, name_len);
1241 }
1242 if (*pOplock & REQ_OPLOCK)
1243 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001244 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001245 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001246
Steve Frencha9d02ad2005-08-24 23:06:05 -07001247 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001248 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001249 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1250 /* set file as system file if special file such
1251 as fifo and server expecting SFU style and
1252 no Unix extensions */
1253
Steve French790fe572007-07-07 19:25:05 +00001254 if (create_options & CREATE_OPTION_SPECIAL)
1255 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001256 else /* BB FIXME BB */
1257 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001258
Jeff Layton67750fb2008-05-09 22:28:02 +00001259 if (create_options & CREATE_OPTION_READONLY)
1260 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001261
1262 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001263/* pSMB->CreateOptions = cpu_to_le32(create_options &
1264 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001265 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001266
1267 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001268 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001269 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001270 inc_rfc1001_len(pSMB, count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001271
1272 pSMB->ByteCount = cpu_to_le16(count);
1273 /* long_op set to 1 to allow for oplock break timeouts */
1274 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001275 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001276 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001277 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001278 cFYI(1, "Error in Open = %d", rc);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001279 } else {
1280 /* BB verify if wct == 15 */
1281
Steve French582d21e2008-05-13 04:54:12 +00001282/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001283
1284 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1285 /* Let caller know file was created so we can set the mode. */
1286 /* Do we care about the CreateAction in any other cases? */
1287 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001288/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001289 *pOplock |= CIFS_CREATE_ACTION; */
1290 /* BB FIXME END */
1291
Steve French790fe572007-07-07 19:25:05 +00001292 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001293 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1294 pfile_info->LastAccessTime = 0; /* BB fixme */
1295 pfile_info->LastWriteTime = 0; /* BB fixme */
1296 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001297 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001298 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001299 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001300 pfile_info->AllocationSize =
1301 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1302 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001303 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001304 pfile_info->DeletePending = 0;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001305 }
1306 }
1307
1308 cifs_buf_release(pSMB);
1309 if (rc == -EAGAIN)
1310 goto OldOpenRetry;
1311 return rc;
1312}
1313
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001315CIFSSMBOpen(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001317 const int access_flags, const int create_options, __u16 *netfid,
1318 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001319 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320{
1321 int rc = -EACCES;
1322 OPEN_REQ *pSMB = NULL;
1323 OPEN_RSP *pSMBr = NULL;
1324 int bytes_returned;
1325 int name_len;
1326 __u16 count;
1327
1328openRetry:
1329 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1330 (void **) &pSMBr);
1331 if (rc)
1332 return rc;
1333
1334 pSMB->AndXCommand = 0xFF; /* none */
1335
1336 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1337 count = 1; /* account for one byte pad to word boundary */
1338 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001339 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1340 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341 name_len++; /* trailing null */
1342 name_len *= 2;
1343 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001344 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345 count = 0; /* no pad */
1346 name_len = strnlen(fileName, PATH_MAX);
1347 name_len++; /* trailing null */
1348 pSMB->NameLength = cpu_to_le16(name_len);
1349 strncpy(pSMB->fileName, fileName, name_len);
1350 }
1351 if (*pOplock & REQ_OPLOCK)
1352 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001353 else if (*pOplock & REQ_BATCHOPLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1356 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -07001357 /* set file as system file if special file such
1358 as fifo and server expecting SFU style and
1359 no Unix extensions */
Steve French790fe572007-07-07 19:25:05 +00001360 if (create_options & CREATE_OPTION_SPECIAL)
Steve Frencheda3c0292005-07-21 15:20:28 -07001361 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1362 else
1363 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Jeff Layton67750fb2008-05-09 22:28:02 +00001364
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365 /* XP does not handle ATTR_POSIX_SEMANTICS */
1366 /* but it helps speed up case sensitive checks for other
1367 servers such as Samba */
1368 if (tcon->ses->capabilities & CAP_UNIX)
1369 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1370
Jeff Layton67750fb2008-05-09 22:28:02 +00001371 if (create_options & CREATE_OPTION_READONLY)
1372 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1373
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1375 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -07001376 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001377 /* BB Expirement with various impersonation levels and verify */
1378 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379 pSMB->SecurityFlags =
1380 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1381
1382 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001383 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384
1385 pSMB->ByteCount = cpu_to_le16(count);
1386 /* long_op set to 1 to allow for oplock break timeouts */
1387 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001388 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001389 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001391 cFYI(1, "Error in Open = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392 } else {
Steve French09d1db52005-04-28 22:41:08 -07001393 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1395 /* Let caller know file was created so we can set the mode. */
1396 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001397 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve French50c2f752007-07-13 00:33:32 +00001398 *pOplock |= CIFS_CREATE_ACTION;
Steve French790fe572007-07-07 19:25:05 +00001399 if (pfile_info) {
Steve French61e74802008-12-03 00:57:54 +00001400 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1401 36 /* CreationTime to Attributes */);
1402 /* the file_info buf is endian converted by caller */
1403 pfile_info->AllocationSize = pSMBr->AllocationSize;
1404 pfile_info->EndOfFile = pSMBr->EndOfFile;
1405 pfile_info->NumberOfLinks = cpu_to_le32(1);
1406 pfile_info->DeletePending = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001409
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410 cifs_buf_release(pSMB);
1411 if (rc == -EAGAIN)
1412 goto openRetry;
1413 return rc;
1414}
1415
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001416/*
1417 * Discard any remaining data in the current SMB. To do this, we borrow the
1418 * current bigbuf.
1419 */
1420static int
1421cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1422{
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001423 unsigned int rfclen = get_rfc1002_length(server->smallbuf);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001424 int remaining = rfclen + 4 - server->total_read;
1425 struct cifs_readdata *rdata = mid->callback_data;
1426
1427 while (remaining > 0) {
1428 int length;
1429
1430 length = cifs_read_from_socket(server, server->bigbuf,
1431 min_t(unsigned int, remaining,
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001432 CIFSMaxBufSize + MAX_HEADER_SIZE(server)));
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001433 if (length < 0)
1434 return length;
1435 server->total_read += length;
1436 remaining -= length;
1437 }
1438
1439 dequeue_mid(mid, rdata->result);
1440 return 0;
1441}
1442
Pavel Shilovsky09a47072012-09-18 16:20:29 -07001443int
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001444cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1445{
1446 int length, len;
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001447 unsigned int data_offset, data_len;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001448 struct cifs_readdata *rdata = mid->callback_data;
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001449 char *buf = server->smallbuf;
1450 unsigned int buflen = get_rfc1002_length(buf) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001451
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001452 cFYI(1, "%s: mid=%llu offset=%llu bytes=%u", __func__,
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001453 mid->mid, rdata->offset, rdata->bytes);
1454
1455 /*
1456 * read the rest of READ_RSP header (sans Data array), or whatever we
1457 * can if there's not enough data. At this point, we've read down to
1458 * the Mid.
1459 */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001460 len = min_t(unsigned int, buflen, server->vals->read_rsp_size) -
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001461 HEADER_SIZE(server) + 1;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001462
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001463 rdata->iov[0].iov_base = buf + HEADER_SIZE(server) - 1;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001464 rdata->iov[0].iov_len = len;
1465
1466 length = cifs_readv_from_socket(server, rdata->iov, 1, len);
1467 if (length < 0)
1468 return length;
1469 server->total_read += length;
1470
1471 /* Was the SMB read successful? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001472 rdata->result = server->ops->map_error(buf, false);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001473 if (rdata->result != 0) {
1474 cFYI(1, "%s: server returned error %d", __func__,
1475 rdata->result);
1476 return cifs_readv_discard(server, mid);
1477 }
1478
1479 /* Is there enough to get to the rest of the READ_RSP header? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001480 if (server->total_read < server->vals->read_rsp_size) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001481 cFYI(1, "%s: server returned short header. got=%u expected=%zu",
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001482 __func__, server->total_read,
1483 server->vals->read_rsp_size);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001484 rdata->result = -EIO;
1485 return cifs_readv_discard(server, mid);
1486 }
1487
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001488 data_offset = server->ops->read_data_offset(buf) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001489 if (data_offset < server->total_read) {
1490 /*
1491 * win2k8 sometimes sends an offset of 0 when the read
1492 * is beyond the EOF. Treat it as if the data starts just after
1493 * the header.
1494 */
1495 cFYI(1, "%s: data offset (%u) inside read response header",
1496 __func__, data_offset);
1497 data_offset = server->total_read;
1498 } else if (data_offset > MAX_CIFS_SMALL_BUFFER_SIZE) {
1499 /* data_offset is beyond the end of smallbuf */
1500 cFYI(1, "%s: data offset (%u) beyond end of smallbuf",
1501 __func__, data_offset);
1502 rdata->result = -EIO;
1503 return cifs_readv_discard(server, mid);
1504 }
1505
1506 cFYI(1, "%s: total_read=%u data_offset=%u", __func__,
1507 server->total_read, data_offset);
1508
1509 len = data_offset - server->total_read;
1510 if (len > 0) {
1511 /* read any junk before data into the rest of smallbuf */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001512 rdata->iov[0].iov_base = buf + server->total_read;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001513 rdata->iov[0].iov_len = len;
1514 length = cifs_readv_from_socket(server, rdata->iov, 1, len);
1515 if (length < 0)
1516 return length;
1517 server->total_read += length;
1518 }
1519
1520 /* set up first iov for signature check */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001521 rdata->iov[0].iov_base = buf;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001522 rdata->iov[0].iov_len = server->total_read;
1523 cFYI(1, "0: iov_base=%p iov_len=%zu",
1524 rdata->iov[0].iov_base, rdata->iov[0].iov_len);
1525
1526 /* how much data is in the response? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001527 data_len = server->ops->read_data_length(buf);
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001528 if (data_offset + data_len > buflen) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001529 /* data_len is corrupt -- discard frame */
1530 rdata->result = -EIO;
1531 return cifs_readv_discard(server, mid);
1532 }
1533
1534 /* marshal up the page array */
Jeff Layton3cf003c2012-07-11 09:09:36 -04001535 cifs_kmap_lock();
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001536 len = rdata->marshal_iov(rdata, data_len);
Jeff Layton3cf003c2012-07-11 09:09:36 -04001537 cifs_kmap_unlock();
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001538 data_len -= len;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001539
1540 /* issue the read if we have any iovecs left to fill */
1541 if (rdata->nr_iov > 1) {
1542 length = cifs_readv_from_socket(server, &rdata->iov[1],
1543 rdata->nr_iov - 1, len);
1544 if (length < 0)
1545 return length;
1546 server->total_read += length;
1547 } else {
1548 length = 0;
1549 }
1550
1551 rdata->bytes = length;
1552
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001553 cFYI(1, "total_read=%u buflen=%u remaining=%u", server->total_read,
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001554 buflen, data_len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001555
1556 /* discard anything left over */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001557 if (server->total_read < buflen)
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001558 return cifs_readv_discard(server, mid);
1559
1560 dequeue_mid(mid, false);
1561 return length;
1562}
1563
1564static void
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001565cifs_readv_callback(struct mid_q_entry *mid)
1566{
1567 struct cifs_readdata *rdata = mid->callback_data;
1568 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1569 struct TCP_Server_Info *server = tcon->ses->server;
1570
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001571 cFYI(1, "%s: mid=%llu state=%d result=%d bytes=%u", __func__,
1572 mid->mid, mid->mid_state, rdata->result, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001573
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001574 switch (mid->mid_state) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001575 case MID_RESPONSE_RECEIVED:
1576 /* result already set, check signature */
1577 if (server->sec_mode &
1578 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
Steve French985e4ff02012-08-03 09:42:45 -05001579 int rc = 0;
1580
1581 rc = cifs_verify_signature(rdata->iov, rdata->nr_iov,
1582 server,
1583 mid->sequence_number + 1);
1584 if (rc)
1585 cERROR(1, "SMB signature verification returned "
1586 "error = %d", rc);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001587 }
1588 /* FIXME: should this be counted toward the initiating task? */
1589 task_io_account_read(rdata->bytes);
1590 cifs_stats_bytes_read(tcon, rdata->bytes);
1591 break;
1592 case MID_REQUEST_SUBMITTED:
1593 case MID_RETRY_NEEDED:
1594 rdata->result = -EAGAIN;
1595 break;
1596 default:
1597 rdata->result = -EIO;
1598 }
1599
Jeff Laytonda472fc2012-03-23 14:40:53 -04001600 queue_work(cifsiod_wq, &rdata->work);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001601 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04001602 add_credits(server, 1, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001603}
1604
1605/* cifs_async_readv - send an async write, and set up mid to handle result */
1606int
1607cifs_async_readv(struct cifs_readdata *rdata)
1608{
1609 int rc;
1610 READ_REQ *smb = NULL;
1611 int wct;
1612 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1613
1614 cFYI(1, "%s: offset=%llu bytes=%u", __func__,
1615 rdata->offset, rdata->bytes);
1616
1617 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1618 wct = 12;
1619 else {
1620 wct = 10; /* old style read */
1621 if ((rdata->offset >> 32) > 0) {
1622 /* can not handle this big offset for old */
1623 return -EIO;
1624 }
1625 }
1626
1627 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **)&smb);
1628 if (rc)
1629 return rc;
1630
1631 smb->hdr.Pid = cpu_to_le16((__u16)rdata->pid);
1632 smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16));
1633
1634 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07001635 smb->Fid = rdata->cfile->fid.netfid;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001636 smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF);
1637 if (wct == 12)
1638 smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32);
1639 smb->Remaining = 0;
1640 smb->MaxCount = cpu_to_le16(rdata->bytes & 0xFFFF);
1641 smb->MaxCountHigh = cpu_to_le32(rdata->bytes >> 16);
1642 if (wct == 12)
1643 smb->ByteCount = 0;
1644 else {
1645 /* old style read */
1646 struct smb_com_readx_req *smbr =
1647 (struct smb_com_readx_req *)smb;
1648 smbr->ByteCount = 0;
1649 }
1650
1651 /* 4 for RFC1001 length + 1 for BCC */
1652 rdata->iov[0].iov_base = smb;
1653 rdata->iov[0].iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
1654
Jeff Layton6993f742012-05-16 07:13:17 -04001655 kref_get(&rdata->refcount);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001656 rc = cifs_call_async(tcon->ses->server, rdata->iov, 1,
1657 cifs_readv_receive, cifs_readv_callback,
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04001658 rdata, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001659
1660 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001661 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Jeff Layton6993f742012-05-16 07:13:17 -04001662 else
1663 kref_put(&rdata->refcount, cifs_readdata_release);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001664
1665 cifs_small_buf_release(smb);
1666 return rc;
1667}
1668
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001670CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
1671 unsigned int *nbytes, char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672{
1673 int rc = -EACCES;
1674 READ_REQ *pSMB = NULL;
1675 READ_RSP *pSMBr = NULL;
1676 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001677 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001678 int resp_buf_type = 0;
1679 struct kvec iov[1];
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001680 __u32 pid = io_parms->pid;
1681 __u16 netfid = io_parms->netfid;
1682 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001683 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001684 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685
Joe Perchesb6b38f72010-04-21 03:50:45 +00001686 cFYI(1, "Reading %d bytes on fid %d", count, netfid);
Steve French790fe572007-07-07 19:25:05 +00001687 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001688 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001689 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001690 wct = 10; /* old style read */
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001691 if ((offset >> 32) > 0) {
Steve French4c3130e2008-12-09 00:28:16 +00001692 /* can not handle this big offset for old */
1693 return -EIO;
1694 }
1695 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696
1697 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001698 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699 if (rc)
1700 return rc;
1701
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001702 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1703 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1704
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705 /* tcon and ses pointer are checked in smb_init */
1706 if (tcon->ses->server == NULL)
1707 return -ECONNABORTED;
1708
Steve Frenchec637e32005-12-12 20:53:18 -08001709 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710 pSMB->Fid = netfid;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001711 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001712 if (wct == 12)
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001713 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001714
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715 pSMB->Remaining = 0;
1716 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1717 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001718 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001719 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1720 else {
1721 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001722 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001723 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001724 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001725 }
Steve Frenchec637e32005-12-12 20:53:18 -08001726
1727 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001728 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve Frencha761ac52007-10-18 21:45:27 +00001729 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Jeff Layton77499812011-01-11 07:24:23 -05001730 &resp_buf_type, CIFS_LOG_ERROR);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001731 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001732 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001734 cERROR(1, "Send error in read = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735 } else {
1736 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1737 data_length = data_length << 16;
1738 data_length += le16_to_cpu(pSMBr->DataLength);
1739 *nbytes = data_length;
1740
1741 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001742 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743 || (data_length > count)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001744 cFYI(1, "bad length %d for count %d",
1745 data_length, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746 rc = -EIO;
1747 *nbytes = 0;
1748 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001749 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001750 le16_to_cpu(pSMBr->DataOffset);
1751/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001752 cERROR(1, "Faulting on read rc = %d",rc);
Steve French50c2f752007-07-13 00:33:32 +00001753 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001754 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001755 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001756 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757 }
1758 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759
Steve French4b8f9302006-02-26 16:41:18 +00001760/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001761 if (*buf) {
1762 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001763 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001764 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001765 cifs_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001766 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001767 /* return buffer to caller to free */
1768 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001769 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001770 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001771 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001772 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001773 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001774
1775 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776 since file handle passed in no longer valid */
1777 return rc;
1778}
1779
Steve Frenchec637e32005-12-12 20:53:18 -08001780
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001782CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001783 unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001784 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785{
1786 int rc = -EACCES;
1787 WRITE_REQ *pSMB = NULL;
1788 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001789 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001790 __u32 bytes_sent;
1791 __u16 byte_count;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001792 __u32 pid = io_parms->pid;
1793 __u16 netfid = io_parms->netfid;
1794 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001795 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001796 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797
Steve Frencha24e2d72010-04-03 17:20:21 +00001798 *nbytes = 0;
1799
Joe Perchesb6b38f72010-04-21 03:50:45 +00001800 /* cFYI(1, "write at %lld %d bytes", offset, count);*/
Steve French790fe572007-07-07 19:25:05 +00001801 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001802 return -ECONNABORTED;
1803
Steve French790fe572007-07-07 19:25:05 +00001804 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001805 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001806 else {
Steve French1c955182005-08-30 20:58:07 -07001807 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001808 if ((offset >> 32) > 0) {
1809 /* can not handle big offset for old srv */
1810 return -EIO;
1811 }
1812 }
Steve French1c955182005-08-30 20:58:07 -07001813
1814 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815 (void **) &pSMBr);
1816 if (rc)
1817 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001818
1819 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1820 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1821
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822 /* tcon and ses pointer are checked in smb_init */
1823 if (tcon->ses->server == NULL)
1824 return -ECONNABORTED;
1825
1826 pSMB->AndXCommand = 0xFF; /* none */
1827 pSMB->Fid = netfid;
1828 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001829 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001830 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001831
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832 pSMB->Reserved = 0xFFFFFFFF;
1833 pSMB->WriteMode = 0;
1834 pSMB->Remaining = 0;
1835
Steve French50c2f752007-07-13 00:33:32 +00001836 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837 can send more if LARGE_WRITE_X capability returned by the server and if
1838 our buffer is big enough or if we convert to iovecs on socket writes
1839 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001840 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1842 } else {
1843 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1844 & ~0xFF;
1845 }
1846
1847 if (bytes_sent > count)
1848 bytes_sent = count;
1849 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001850 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001851 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001852 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001853 else if (ubuf) {
1854 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855 cifs_buf_release(pSMB);
1856 return -EFAULT;
1857 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001858 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859 /* No buffer */
1860 cifs_buf_release(pSMB);
1861 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001862 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001863 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001864 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001865 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001866 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001867
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1869 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001870 inc_rfc1001_len(pSMB, byte_count);
Steve French1c955182005-08-30 20:58:07 -07001871
Steve French790fe572007-07-07 19:25:05 +00001872 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001873 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001874 else { /* old style write has byte count 4 bytes earlier
1875 so 4 bytes pad */
1876 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001877 (struct smb_com_writex_req *)pSMB;
1878 pSMBW->ByteCount = cpu_to_le16(byte_count);
1879 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001880
1881 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1882 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001883 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00001885 cFYI(1, "Send error in write = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886 } else {
1887 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1888 *nbytes = (*nbytes) << 16;
1889 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301890
1891 /*
1892 * Mask off high 16 bits when bytes written as returned by the
1893 * server is greater than bytes requested by the client. Some
1894 * OS/2 servers are known to set incorrect CountHigh values.
1895 */
1896 if (*nbytes > count)
1897 *nbytes &= 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898 }
1899
1900 cifs_buf_release(pSMB);
1901
Steve French50c2f752007-07-13 00:33:32 +00001902 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903 since file handle passed in no longer valid */
1904
1905 return rc;
1906}
1907
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001908void
1909cifs_writedata_release(struct kref *refcount)
1910{
1911 struct cifs_writedata *wdata = container_of(refcount,
1912 struct cifs_writedata, refcount);
1913
1914 if (wdata->cfile)
1915 cifsFileInfo_put(wdata->cfile);
1916
1917 kfree(wdata);
1918}
1919
1920/*
1921 * Write failed with a retryable error. Resend the write request. It's also
1922 * possible that the page was redirtied so re-clean the page.
1923 */
1924static void
1925cifs_writev_requeue(struct cifs_writedata *wdata)
1926{
1927 int i, rc;
1928 struct inode *inode = wdata->cfile->dentry->d_inode;
Pavel Shilovskyc9de5c82012-09-18 16:20:29 -07001929 struct TCP_Server_Info *server;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001930
1931 for (i = 0; i < wdata->nr_pages; i++) {
1932 lock_page(wdata->pages[i]);
1933 clear_page_dirty_for_io(wdata->pages[i]);
1934 }
1935
1936 do {
Pavel Shilovskyc9de5c82012-09-18 16:20:29 -07001937 server = tlink_tcon(wdata->cfile->tlink)->ses->server;
1938 rc = server->ops->async_writev(wdata);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001939 } while (rc == -EAGAIN);
1940
1941 for (i = 0; i < wdata->nr_pages; i++) {
1942 if (rc != 0)
1943 SetPageError(wdata->pages[i]);
1944 unlock_page(wdata->pages[i]);
1945 }
1946
1947 mapping_set_error(inode->i_mapping, rc);
1948 kref_put(&wdata->refcount, cifs_writedata_release);
1949}
1950
Jeff Laytonc2e87642012-03-23 14:40:55 -04001951void
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001952cifs_writev_complete(struct work_struct *work)
1953{
1954 struct cifs_writedata *wdata = container_of(work,
1955 struct cifs_writedata, work);
1956 struct inode *inode = wdata->cfile->dentry->d_inode;
1957 int i = 0;
1958
1959 if (wdata->result == 0) {
Jeff Layton597b0272012-03-23 14:40:56 -04001960 spin_lock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001961 cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
Jeff Layton597b0272012-03-23 14:40:56 -04001962 spin_unlock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001963 cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
1964 wdata->bytes);
1965 } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
1966 return cifs_writev_requeue(wdata);
1967
1968 for (i = 0; i < wdata->nr_pages; i++) {
1969 struct page *page = wdata->pages[i];
1970 if (wdata->result == -EAGAIN)
1971 __set_page_dirty_nobuffers(page);
1972 else if (wdata->result < 0)
1973 SetPageError(page);
1974 end_page_writeback(page);
1975 page_cache_release(page);
1976 }
1977 if (wdata->result != -EAGAIN)
1978 mapping_set_error(inode->i_mapping, wdata->result);
1979 kref_put(&wdata->refcount, cifs_writedata_release);
1980}
1981
1982struct cifs_writedata *
Jeff Laytonc2e87642012-03-23 14:40:55 -04001983cifs_writedata_alloc(unsigned int nr_pages, work_func_t complete)
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001984{
1985 struct cifs_writedata *wdata;
1986
1987 /* this would overflow */
1988 if (nr_pages == 0) {
1989 cERROR(1, "%s: called with nr_pages == 0!", __func__);
1990 return NULL;
1991 }
1992
1993 /* writedata + number of page pointers */
1994 wdata = kzalloc(sizeof(*wdata) +
1995 sizeof(struct page *) * (nr_pages - 1), GFP_NOFS);
1996 if (wdata != NULL) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001997 kref_init(&wdata->refcount);
Jeff Laytonda82f7e2012-03-23 14:40:56 -04001998 INIT_LIST_HEAD(&wdata->list);
1999 init_completion(&wdata->done);
2000 INIT_WORK(&wdata->work, complete);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002001 }
2002 return wdata;
2003}
2004
2005/*
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04002006 * Check the mid_state and signature on received buffer (if any), and queue the
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002007 * workqueue completion task.
2008 */
2009static void
2010cifs_writev_callback(struct mid_q_entry *mid)
2011{
2012 struct cifs_writedata *wdata = mid->callback_data;
Steve French96daf2b2011-05-27 04:34:02 +00002013 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002014 unsigned int written;
2015 WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
2016
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04002017 switch (mid->mid_state) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002018 case MID_RESPONSE_RECEIVED:
2019 wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
2020 if (wdata->result != 0)
2021 break;
2022
2023 written = le16_to_cpu(smb->CountHigh);
2024 written <<= 16;
2025 written += le16_to_cpu(smb->Count);
2026 /*
2027 * Mask off high 16 bits when bytes written as returned
2028 * by the server is greater than bytes requested by the
2029 * client. OS/2 servers are known to set incorrect
2030 * CountHigh values.
2031 */
2032 if (written > wdata->bytes)
2033 written &= 0xFFFF;
2034
2035 if (written < wdata->bytes)
2036 wdata->result = -ENOSPC;
2037 else
2038 wdata->bytes = written;
2039 break;
2040 case MID_REQUEST_SUBMITTED:
2041 case MID_RETRY_NEEDED:
2042 wdata->result = -EAGAIN;
2043 break;
2044 default:
2045 wdata->result = -EIO;
2046 break;
2047 }
2048
Jeff Laytonda472fc2012-03-23 14:40:53 -04002049 queue_work(cifsiod_wq, &wdata->work);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002050 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002051 add_credits(tcon->ses->server, 1, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002052}
2053
2054/* cifs_async_writev - send an async write, and set up mid to handle result */
2055int
2056cifs_async_writev(struct cifs_writedata *wdata)
2057{
2058 int i, rc = -EACCES;
2059 WRITE_REQ *smb = NULL;
2060 int wct;
Steve French96daf2b2011-05-27 04:34:02 +00002061 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002062 struct kvec *iov = NULL;
2063
2064 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
2065 wct = 14;
2066 } else {
2067 wct = 12;
2068 if (wdata->offset >> 32 > 0) {
2069 /* can not handle big offset for old srv */
2070 return -EIO;
2071 }
2072 }
2073
2074 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
2075 if (rc)
2076 goto async_writev_out;
2077
2078 /* 1 iov per page + 1 for header */
2079 iov = kzalloc((wdata->nr_pages + 1) * sizeof(*iov), GFP_NOFS);
2080 if (iov == NULL) {
2081 rc = -ENOMEM;
2082 goto async_writev_out;
2083 }
2084
Jeff Laytonfe5f5d22012-03-23 14:40:55 -04002085 smb->hdr.Pid = cpu_to_le16((__u16)wdata->pid);
2086 smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16));
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002087
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002088 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07002089 smb->Fid = wdata->cfile->fid.netfid;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002090 smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
2091 if (wct == 14)
2092 smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
2093 smb->Reserved = 0xFFFFFFFF;
2094 smb->WriteMode = 0;
2095 smb->Remaining = 0;
2096
2097 smb->DataOffset =
2098 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
2099
2100 /* 4 for RFC1001 length + 1 for BCC */
2101 iov[0].iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4 + 1;
2102 iov[0].iov_base = smb;
2103
Jeff Laytone9492872012-03-23 14:40:56 -04002104 /*
2105 * This function should marshal up the page array into the kvec
2106 * array, reserving [0] for the header. It should kmap the pages
2107 * and set the iov_len properly for each one. It may also set
2108 * wdata->bytes too.
2109 */
Jeff Layton3cf003c2012-07-11 09:09:36 -04002110 cifs_kmap_lock();
Jeff Laytone9492872012-03-23 14:40:56 -04002111 wdata->marshal_iov(iov, wdata);
Jeff Layton3cf003c2012-07-11 09:09:36 -04002112 cifs_kmap_unlock();
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002113
2114 cFYI(1, "async write at %llu %u bytes", wdata->offset, wdata->bytes);
2115
2116 smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
2117 smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16);
2118
2119 if (wct == 14) {
2120 inc_rfc1001_len(&smb->hdr, wdata->bytes + 1);
2121 put_bcc(wdata->bytes + 1, &smb->hdr);
2122 } else {
2123 /* wct == 12 */
2124 struct smb_com_writex_req *smbw =
2125 (struct smb_com_writex_req *)smb;
2126 inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
2127 put_bcc(wdata->bytes + 5, &smbw->hdr);
2128 iov[0].iov_len += 4; /* pad bigger by four bytes */
2129 }
2130
2131 kref_get(&wdata->refcount);
2132 rc = cifs_call_async(tcon->ses->server, iov, wdata->nr_pages + 1,
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002133 NULL, cifs_writev_callback, wdata, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002134
2135 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002136 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002137 else
2138 kref_put(&wdata->refcount, cifs_writedata_release);
2139
2140 /* send is done, unmap pages */
2141 for (i = 0; i < wdata->nr_pages; i++)
2142 kunmap(wdata->pages[i]);
2143
2144async_writev_out:
2145 cifs_small_buf_release(smb);
2146 kfree(iov);
2147 return rc;
2148}
2149
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002150int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002151CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002152 unsigned int *nbytes, struct kvec *iov, int n_vec,
2153 const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002154{
2155 int rc = -EACCES;
2156 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08002157 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002158 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08002159 int resp_buf_type = 0;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002160 __u32 pid = io_parms->pid;
2161 __u16 netfid = io_parms->netfid;
2162 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00002163 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002164 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002165
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04002166 *nbytes = 0;
2167
Joe Perchesb6b38f72010-04-21 03:50:45 +00002168 cFYI(1, "write2 at %lld %d bytes", (long long)offset, count);
Steve Frenchff7feac2005-11-15 16:45:16 -08002169
Steve French4c3130e2008-12-09 00:28:16 +00002170 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07002171 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00002172 } else {
Steve French8cc64c62005-10-03 13:49:43 -07002173 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00002174 if ((offset >> 32) > 0) {
2175 /* can not handle big offset for old srv */
2176 return -EIO;
2177 }
2178 }
Steve French8cc64c62005-10-03 13:49:43 -07002179 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002180 if (rc)
2181 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002182
2183 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
2184 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
2185
Linus Torvalds1da177e2005-04-16 15:20:36 -07002186 /* tcon and ses pointer are checked in smb_init */
2187 if (tcon->ses->server == NULL)
2188 return -ECONNABORTED;
2189
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002190 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002191 pSMB->Fid = netfid;
2192 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00002193 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002194 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195 pSMB->Reserved = 0xFFFFFFFF;
2196 pSMB->WriteMode = 0;
2197 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002198
Linus Torvalds1da177e2005-04-16 15:20:36 -07002199 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00002200 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002201
Steve French3e844692005-10-03 13:37:24 -07002202 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
2203 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002204 /* header + 1 byte pad */
2205 smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
Steve French790fe572007-07-07 19:25:05 +00002206 if (wct == 14)
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002207 inc_rfc1001_len(pSMB, count + 1);
Steve French8cc64c62005-10-03 13:49:43 -07002208 else /* wct == 12 */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002209 inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
Steve French790fe572007-07-07 19:25:05 +00002210 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002211 pSMB->ByteCount = cpu_to_le16(count + 1);
2212 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00002213 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07002214 (struct smb_com_writex_req *)pSMB;
2215 pSMBW->ByteCount = cpu_to_le16(count + 5);
2216 }
Steve French3e844692005-10-03 13:37:24 -07002217 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00002218 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08002219 iov[0].iov_len = smb_hdr_len + 4;
2220 else /* wct == 12 pad bigger by four bytes */
2221 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00002222
Steve French3e844692005-10-03 13:37:24 -07002223
Steve Frenchec637e32005-12-12 20:53:18 -08002224 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French133672e2007-11-13 22:41:37 +00002225 long_op);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002226 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002227 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002228 cFYI(1, "Send error Write2 = %d", rc);
Steve French790fe572007-07-07 19:25:05 +00002229 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08002230 /* presumably this can not happen, but best to be safe */
2231 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002232 } else {
Steve Frenchad7a2922008-02-07 23:25:02 +00002233 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002234 *nbytes = le16_to_cpu(pSMBr->CountHigh);
2235 *nbytes = (*nbytes) << 16;
2236 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05302237
2238 /*
2239 * Mask off high 16 bits when bytes written as returned by the
2240 * server is greater than bytes requested by the client. OS/2
2241 * servers are known to set incorrect CountHigh values.
2242 */
2243 if (*nbytes > count)
2244 *nbytes &= 0xFFFF;
Steve French50c2f752007-07-13 00:33:32 +00002245 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002246
Steve French4b8f9302006-02-26 16:41:18 +00002247/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00002248 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002249 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00002250 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002251 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002252
Steve French50c2f752007-07-13 00:33:32 +00002253 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254 since file handle passed in no longer valid */
2255
2256 return rc;
2257}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002258
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002259int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon,
2260 const __u16 netfid, const __u8 lock_type, const __u32 num_unlock,
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002261 const __u32 num_lock, LOCKING_ANDX_RANGE *buf)
2262{
2263 int rc = 0;
2264 LOCK_REQ *pSMB = NULL;
2265 struct kvec iov[2];
2266 int resp_buf_type;
2267 __u16 count;
2268
2269 cFYI(1, "cifs_lockv num lock %d num unlock %d", num_lock, num_unlock);
2270
2271 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2272 if (rc)
2273 return rc;
2274
2275 pSMB->Timeout = 0;
2276 pSMB->NumberOfLocks = cpu_to_le16(num_lock);
2277 pSMB->NumberOfUnlocks = cpu_to_le16(num_unlock);
2278 pSMB->LockType = lock_type;
2279 pSMB->AndXCommand = 0xFF; /* none */
2280 pSMB->Fid = netfid; /* netfid stays le */
2281
2282 count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2283 inc_rfc1001_len(pSMB, count);
2284 pSMB->ByteCount = cpu_to_le16(count);
2285
2286 iov[0].iov_base = (char *)pSMB;
2287 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 -
2288 (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2289 iov[1].iov_base = (char *)buf;
2290 iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2291
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002292 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002293 rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP);
2294 if (rc)
2295 cFYI(1, "Send error in cifs_lockv = %d", rc);
2296
2297 return rc;
2298}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002299
Linus Torvalds1da177e2005-04-16 15:20:36 -07002300int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002301CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002302 const __u16 smb_file_id, const __u32 netpid, const __u64 len,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002303 const __u64 offset, const __u32 numUnlock,
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002304 const __u32 numLock, const __u8 lockType,
2305 const bool waitFlag, const __u8 oplock_level)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002306{
2307 int rc = 0;
2308 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002309/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310 int bytes_returned;
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002311 int flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002312 __u16 count;
2313
Joe Perchesb6b38f72010-04-21 03:50:45 +00002314 cFYI(1, "CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock);
Steve French46810cb2005-04-28 22:41:09 -07002315 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2316
Linus Torvalds1da177e2005-04-16 15:20:36 -07002317 if (rc)
2318 return rc;
2319
Steve French790fe572007-07-07 19:25:05 +00002320 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002321 /* no response expected */
2322 flags = CIFS_ASYNC_OP | CIFS_OBREAK_OP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00002324 } else if (waitFlag) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002325 flags = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002326 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
2327 } else {
2328 pSMB->Timeout = 0;
2329 }
2330
2331 pSMB->NumberOfLocks = cpu_to_le16(numLock);
2332 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
2333 pSMB->LockType = lockType;
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002334 pSMB->OplockLevel = oplock_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002335 pSMB->AndXCommand = 0xFF; /* none */
2336 pSMB->Fid = smb_file_id; /* netfid stays le */
2337
Steve French790fe572007-07-07 19:25:05 +00002338 if ((numLock != 0) || (numUnlock != 0)) {
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002339 pSMB->Locks[0].Pid = cpu_to_le16(netpid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002340 /* BB where to store pid high? */
2341 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
2342 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
2343 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
2344 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
2345 count = sizeof(LOCKING_ANDX_RANGE);
2346 } else {
2347 /* oplock break */
2348 count = 0;
2349 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002350 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002351 pSMB->ByteCount = cpu_to_le16(count);
2352
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002353 if (waitFlag) {
2354 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002355 (struct smb_hdr *) pSMB, &bytes_returned);
Steve French133672e2007-11-13 22:41:37 +00002356 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002357 } else {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002358 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, flags);
Steve French133672e2007-11-13 22:41:37 +00002359 /* SMB buffer freed by function above */
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002360 }
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002361 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002362 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002363 cFYI(1, "Send error in Lock = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002364
Steve French50c2f752007-07-13 00:33:32 +00002365 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002366 since file handle passed in no longer valid */
2367 return rc;
2368}
2369
2370int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002371CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002372 const __u16 smb_file_id, const __u32 netpid,
2373 const loff_t start_offset, const __u64 len,
2374 struct file_lock *pLockData, const __u16 lock_type,
2375 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00002376{
2377 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2378 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00002379 struct cifs_posix_lock *parm_data;
2380 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00002381 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00002382 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00002383 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00002384 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00002385 struct kvec iov[1];
Steve French08547b02006-02-28 22:39:25 +00002386
Joe Perchesb6b38f72010-04-21 03:50:45 +00002387 cFYI(1, "Posix Lock");
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002388
Steve French08547b02006-02-28 22:39:25 +00002389 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
2390
2391 if (rc)
2392 return rc;
2393
2394 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
2395
Steve French50c2f752007-07-13 00:33:32 +00002396 params = 6;
Steve French08547b02006-02-28 22:39:25 +00002397 pSMB->MaxSetupCount = 0;
2398 pSMB->Reserved = 0;
2399 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00002400 pSMB->Reserved2 = 0;
2401 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2402 offset = param_offset + params;
2403
Steve French08547b02006-02-28 22:39:25 +00002404 count = sizeof(struct cifs_posix_lock);
2405 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002406 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00002407 pSMB->SetupCount = 1;
2408 pSMB->Reserved3 = 0;
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002409 if (pLockData)
Steve French08547b02006-02-28 22:39:25 +00002410 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2411 else
2412 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2413 byte_count = 3 /* pad */ + params + count;
2414 pSMB->DataCount = cpu_to_le16(count);
2415 pSMB->ParameterCount = cpu_to_le16(params);
2416 pSMB->TotalDataCount = pSMB->DataCount;
2417 pSMB->TotalParameterCount = pSMB->ParameterCount;
2418 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00002419 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00002420 (((char *) &pSMB->hdr.Protocol) + offset);
2421
2422 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00002423 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00002424 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00002425 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00002426 pSMB->Timeout = cpu_to_le32(-1);
2427 } else
2428 pSMB->Timeout = 0;
2429
Pavel Shilovsky4f6bcec2011-10-22 15:33:30 +04002430 parm_data->pid = cpu_to_le32(netpid);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002431 parm_data->start = cpu_to_le64(start_offset);
Steve Frenchcec6815a2006-05-30 18:07:17 +00002432 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00002433
2434 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00002435 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00002436 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
2437 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002438 inc_rfc1001_len(pSMB, byte_count);
Steve French08547b02006-02-28 22:39:25 +00002439 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002440 if (waitFlag) {
2441 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2442 (struct smb_hdr *) pSMBr, &bytes_returned);
2443 } else {
Steve French133672e2007-11-13 22:41:37 +00002444 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002445 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French133672e2007-11-13 22:41:37 +00002446 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
2447 &resp_buf_type, timeout);
2448 pSMB = NULL; /* request buf already freed by SendReceive2. Do
2449 not try to free it twice below on exit */
2450 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002451 }
2452
Steve French08547b02006-02-28 22:39:25 +00002453 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002454 cFYI(1, "Send error in Posix Lock = %d", rc);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002455 } else if (pLockData) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002456 /* lock structure can be returned on get */
2457 __u16 data_offset;
2458 __u16 data_count;
2459 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00002460
Jeff Layton820a8032011-05-04 08:05:26 -04002461 if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002462 rc = -EIO; /* bad smb */
2463 goto plk_err_exit;
2464 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002465 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2466 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00002467 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002468 rc = -EIO;
2469 goto plk_err_exit;
2470 }
2471 parm_data = (struct cifs_posix_lock *)
2472 ((char *)&pSMBr->hdr.Protocol + data_offset);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002473 if (parm_data->lock_type == __constant_cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002474 pLockData->fl_type = F_UNLCK;
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002475 else {
2476 if (parm_data->lock_type ==
2477 __constant_cpu_to_le16(CIFS_RDLCK))
2478 pLockData->fl_type = F_RDLCK;
2479 else if (parm_data->lock_type ==
2480 __constant_cpu_to_le16(CIFS_WRLCK))
2481 pLockData->fl_type = F_WRLCK;
2482
Steve French5443d132011-03-13 05:08:25 +00002483 pLockData->fl_start = le64_to_cpu(parm_data->start);
2484 pLockData->fl_end = pLockData->fl_start +
2485 le64_to_cpu(parm_data->length) - 1;
2486 pLockData->fl_pid = le32_to_cpu(parm_data->pid);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002487 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002488 }
Steve French50c2f752007-07-13 00:33:32 +00002489
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002490plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00002491 if (pSMB)
2492 cifs_small_buf_release(pSMB);
2493
Steve French133672e2007-11-13 22:41:37 +00002494 if (resp_buf_type == CIFS_SMALL_BUFFER)
2495 cifs_small_buf_release(iov[0].iov_base);
2496 else if (resp_buf_type == CIFS_LARGE_BUFFER)
2497 cifs_buf_release(iov[0].iov_base);
2498
Steve French08547b02006-02-28 22:39:25 +00002499 /* Note: On -EAGAIN error only caller can retry on handle based calls
2500 since file handle passed in no longer valid */
2501
2502 return rc;
2503}
2504
2505
2506int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002507CIFSSMBClose(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002508{
2509 int rc = 0;
2510 CLOSE_REQ *pSMB = NULL;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002511 cFYI(1, "In CIFSSMBClose");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002512
2513/* do not retry on dead session on close */
2514 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00002515 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002516 return 0;
2517 if (rc)
2518 return rc;
2519
Linus Torvalds1da177e2005-04-16 15:20:36 -07002520 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00002521 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002522 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002523 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002524 cifs_stats_inc(&tcon->stats.cifs_stats.num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002525 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00002526 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002527 /* EINTR is expected when user ctl-c to kill app */
Joe Perchesb6b38f72010-04-21 03:50:45 +00002528 cERROR(1, "Send error in Close = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529 }
2530 }
2531
Linus Torvalds1da177e2005-04-16 15:20:36 -07002532 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00002533 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002534 rc = 0;
2535
2536 return rc;
2537}
2538
2539int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002540CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Steve Frenchb298f222009-02-21 21:17:43 +00002541{
2542 int rc = 0;
2543 FLUSH_REQ *pSMB = NULL;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002544 cFYI(1, "In CIFSSMBFlush");
Steve Frenchb298f222009-02-21 21:17:43 +00002545
2546 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
2547 if (rc)
2548 return rc;
2549
2550 pSMB->FileID = (__u16) smb_file_id;
2551 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002552 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002553 cifs_stats_inc(&tcon->stats.cifs_stats.num_flushes);
Steve Frenchb298f222009-02-21 21:17:43 +00002554 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002555 cERROR(1, "Send error in Flush = %d", rc);
Steve Frenchb298f222009-02-21 21:17:43 +00002556
2557 return rc;
2558}
2559
2560int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002561CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002562 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002563 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002564{
2565 int rc = 0;
2566 RENAME_REQ *pSMB = NULL;
2567 RENAME_RSP *pSMBr = NULL;
2568 int bytes_returned;
2569 int name_len, name_len2;
2570 __u16 count;
2571
Joe Perchesb6b38f72010-04-21 03:50:45 +00002572 cFYI(1, "In CIFSSMBRename");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002573renameRetry:
2574 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
2575 (void **) &pSMBr);
2576 if (rc)
2577 return rc;
2578
2579 pSMB->BufferFormat = 0x04;
2580 pSMB->SearchAttributes =
2581 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2582 ATTR_DIRECTORY);
2583
2584 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2585 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06002586 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, fromName,
2587 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002588 name_len++; /* trailing null */
2589 name_len *= 2;
2590 pSMB->OldFileName[name_len] = 0x04; /* pad */
2591 /* protocol requires ASCII signature byte on Unicode string */
2592 pSMB->OldFileName[name_len + 1] = 0x00;
2593 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002594 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2595 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002596 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2597 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002598 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002599 name_len = strnlen(fromName, PATH_MAX);
2600 name_len++; /* trailing null */
2601 strncpy(pSMB->OldFileName, fromName, name_len);
2602 name_len2 = strnlen(toName, PATH_MAX);
2603 name_len2++; /* trailing null */
2604 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2605 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2606 name_len2++; /* trailing null */
2607 name_len2++; /* signature byte */
2608 }
2609
2610 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002611 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002612 pSMB->ByteCount = cpu_to_le16(count);
2613
2614 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2615 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002616 cifs_stats_inc(&tcon->stats.cifs_stats.num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002617 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002618 cFYI(1, "Send error in rename = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002619
Linus Torvalds1da177e2005-04-16 15:20:36 -07002620 cifs_buf_release(pSMB);
2621
2622 if (rc == -EAGAIN)
2623 goto renameRetry;
2624
2625 return rc;
2626}
2627
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002628int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002629 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002630 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002631{
2632 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2633 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002634 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635 char *data_offset;
2636 char dummy_string[30];
2637 int rc = 0;
2638 int bytes_returned = 0;
2639 int len_of_str;
2640 __u16 params, param_offset, offset, count, byte_count;
2641
Joe Perchesb6b38f72010-04-21 03:50:45 +00002642 cFYI(1, "Rename to File by handle");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002643 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2644 (void **) &pSMBr);
2645 if (rc)
2646 return rc;
2647
2648 params = 6;
2649 pSMB->MaxSetupCount = 0;
2650 pSMB->Reserved = 0;
2651 pSMB->Flags = 0;
2652 pSMB->Timeout = 0;
2653 pSMB->Reserved2 = 0;
2654 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2655 offset = param_offset + params;
2656
2657 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2658 rename_info = (struct set_file_rename *) data_offset;
2659 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002660 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002661 pSMB->SetupCount = 1;
2662 pSMB->Reserved3 = 0;
2663 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2664 byte_count = 3 /* pad */ + params;
2665 pSMB->ParameterCount = cpu_to_le16(params);
2666 pSMB->TotalParameterCount = pSMB->ParameterCount;
2667 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2668 pSMB->DataOffset = cpu_to_le16(offset);
2669 /* construct random name ".cifs_tmp<inodenum><mid>" */
2670 rename_info->overwrite = cpu_to_le32(1);
2671 rename_info->root_fid = 0;
2672 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002673 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002674 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
Steve Frenchacbbb762012-01-18 22:32:33 -06002675 len_of_str =
2676 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002677 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002678 } else {
Steve Frenchacbbb762012-01-18 22:32:33 -06002679 len_of_str =
2680 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002681 target_name, PATH_MAX, nls_codepage,
2682 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002683 }
2684 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002685 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002686 byte_count += count;
2687 pSMB->DataCount = cpu_to_le16(count);
2688 pSMB->TotalDataCount = pSMB->DataCount;
2689 pSMB->Fid = netfid;
2690 pSMB->InformationLevel =
2691 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2692 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002693 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002694 pSMB->ByteCount = cpu_to_le16(byte_count);
2695 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002696 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002697 cifs_stats_inc(&pTcon->stats.cifs_stats.num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002698 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002699 cFYI(1, "Send error in Rename (by file handle) = %d", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07002700
Linus Torvalds1da177e2005-04-16 15:20:36 -07002701 cifs_buf_release(pSMB);
2702
2703 /* Note: On -EAGAIN error only caller can retry on handle based calls
2704 since file handle passed in no longer valid */
2705
2706 return rc;
2707}
2708
2709int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002710CIFSSMBCopy(const unsigned int xid, struct cifs_tcon *tcon,
2711 const char *fromName, const __u16 target_tid, const char *toName,
2712 const int flags, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002713{
2714 int rc = 0;
2715 COPY_REQ *pSMB = NULL;
2716 COPY_RSP *pSMBr = NULL;
2717 int bytes_returned;
2718 int name_len, name_len2;
2719 __u16 count;
2720
Joe Perchesb6b38f72010-04-21 03:50:45 +00002721 cFYI(1, "In CIFSSMBCopy");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002722copyRetry:
2723 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2724 (void **) &pSMBr);
2725 if (rc)
2726 return rc;
2727
2728 pSMB->BufferFormat = 0x04;
2729 pSMB->Tid2 = target_tid;
2730
2731 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2732
2733 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002734 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2735 fromName, PATH_MAX, nls_codepage,
2736 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002737 name_len++; /* trailing null */
2738 name_len *= 2;
2739 pSMB->OldFileName[name_len] = 0x04; /* pad */
2740 /* protocol requires ASCII signature byte on Unicode string */
2741 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002742 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002743 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2744 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002745 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2746 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002747 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748 name_len = strnlen(fromName, PATH_MAX);
2749 name_len++; /* trailing null */
2750 strncpy(pSMB->OldFileName, fromName, name_len);
2751 name_len2 = strnlen(toName, PATH_MAX);
2752 name_len2++; /* trailing null */
2753 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2754 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2755 name_len2++; /* trailing null */
2756 name_len2++; /* signature byte */
2757 }
2758
2759 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002760 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002761 pSMB->ByteCount = cpu_to_le16(count);
2762
2763 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2764 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2765 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002766 cFYI(1, "Send error in copy = %d with %d files copied",
2767 rc, le16_to_cpu(pSMBr->CopyCount));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002768 }
Steve French0d817bc2008-05-22 02:02:03 +00002769 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002770
2771 if (rc == -EAGAIN)
2772 goto copyRetry;
2773
2774 return rc;
2775}
2776
2777int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002778CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002779 const char *fromName, const char *toName,
2780 const struct nls_table *nls_codepage)
2781{
2782 TRANSACTION2_SPI_REQ *pSMB = NULL;
2783 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2784 char *data_offset;
2785 int name_len;
2786 int name_len_target;
2787 int rc = 0;
2788 int bytes_returned = 0;
2789 __u16 params, param_offset, offset, byte_count;
2790
Joe Perchesb6b38f72010-04-21 03:50:45 +00002791 cFYI(1, "In Symlink Unix style");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002792createSymLinkRetry:
2793 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2794 (void **) &pSMBr);
2795 if (rc)
2796 return rc;
2797
2798 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2799 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06002800 cifs_strtoUTF16((__le16 *) pSMB->FileName, fromName,
2801 /* find define for this maxpathcomponent */
2802 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002803 name_len++; /* trailing null */
2804 name_len *= 2;
2805
Steve French50c2f752007-07-13 00:33:32 +00002806 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002807 name_len = strnlen(fromName, PATH_MAX);
2808 name_len++; /* trailing null */
2809 strncpy(pSMB->FileName, fromName, name_len);
2810 }
2811 params = 6 + name_len;
2812 pSMB->MaxSetupCount = 0;
2813 pSMB->Reserved = 0;
2814 pSMB->Flags = 0;
2815 pSMB->Timeout = 0;
2816 pSMB->Reserved2 = 0;
2817 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002818 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002819 offset = param_offset + params;
2820
2821 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2822 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2823 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06002824 cifs_strtoUTF16((__le16 *) data_offset, toName, PATH_MAX
2825 /* find define for this maxpathcomponent */
2826 , nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002827 name_len_target++; /* trailing null */
2828 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002829 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002830 name_len_target = strnlen(toName, PATH_MAX);
2831 name_len_target++; /* trailing null */
2832 strncpy(data_offset, toName, name_len_target);
2833 }
2834
2835 pSMB->MaxParameterCount = cpu_to_le16(2);
2836 /* BB find exact max on data count below from sess */
2837 pSMB->MaxDataCount = cpu_to_le16(1000);
2838 pSMB->SetupCount = 1;
2839 pSMB->Reserved3 = 0;
2840 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2841 byte_count = 3 /* pad */ + params + name_len_target;
2842 pSMB->DataCount = cpu_to_le16(name_len_target);
2843 pSMB->ParameterCount = cpu_to_le16(params);
2844 pSMB->TotalDataCount = pSMB->DataCount;
2845 pSMB->TotalParameterCount = pSMB->ParameterCount;
2846 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2847 pSMB->DataOffset = cpu_to_le16(offset);
2848 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2849 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002850 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002851 pSMB->ByteCount = cpu_to_le16(byte_count);
2852 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2853 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002854 cifs_stats_inc(&tcon->stats.cifs_stats.num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002855 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002856 cFYI(1, "Send error in SetPathInfo create symlink = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002857
Steve French0d817bc2008-05-22 02:02:03 +00002858 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002859
2860 if (rc == -EAGAIN)
2861 goto createSymLinkRetry;
2862
2863 return rc;
2864}
2865
2866int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002867CIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002868 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002869 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002870{
2871 TRANSACTION2_SPI_REQ *pSMB = NULL;
2872 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2873 char *data_offset;
2874 int name_len;
2875 int name_len_target;
2876 int rc = 0;
2877 int bytes_returned = 0;
2878 __u16 params, param_offset, offset, byte_count;
2879
Joe Perchesb6b38f72010-04-21 03:50:45 +00002880 cFYI(1, "In Create Hard link Unix style");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002881createHardLinkRetry:
2882 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2883 (void **) &pSMBr);
2884 if (rc)
2885 return rc;
2886
2887 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002888 name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, toName,
2889 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002890 name_len++; /* trailing null */
2891 name_len *= 2;
2892
Steve French50c2f752007-07-13 00:33:32 +00002893 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002894 name_len = strnlen(toName, PATH_MAX);
2895 name_len++; /* trailing null */
2896 strncpy(pSMB->FileName, toName, name_len);
2897 }
2898 params = 6 + name_len;
2899 pSMB->MaxSetupCount = 0;
2900 pSMB->Reserved = 0;
2901 pSMB->Flags = 0;
2902 pSMB->Timeout = 0;
2903 pSMB->Reserved2 = 0;
2904 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002905 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002906 offset = param_offset + params;
2907
2908 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2909 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2910 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06002911 cifsConvertToUTF16((__le16 *) data_offset, fromName,
2912 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002913 name_len_target++; /* trailing null */
2914 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002915 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002916 name_len_target = strnlen(fromName, PATH_MAX);
2917 name_len_target++; /* trailing null */
2918 strncpy(data_offset, fromName, name_len_target);
2919 }
2920
2921 pSMB->MaxParameterCount = cpu_to_le16(2);
2922 /* BB find exact max on data count below from sess*/
2923 pSMB->MaxDataCount = cpu_to_le16(1000);
2924 pSMB->SetupCount = 1;
2925 pSMB->Reserved3 = 0;
2926 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2927 byte_count = 3 /* pad */ + params + name_len_target;
2928 pSMB->ParameterCount = cpu_to_le16(params);
2929 pSMB->TotalParameterCount = pSMB->ParameterCount;
2930 pSMB->DataCount = cpu_to_le16(name_len_target);
2931 pSMB->TotalDataCount = pSMB->DataCount;
2932 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2933 pSMB->DataOffset = cpu_to_le16(offset);
2934 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2935 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002936 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002937 pSMB->ByteCount = cpu_to_le16(byte_count);
2938 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2939 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002940 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002941 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002942 cFYI(1, "Send error in SetPathInfo (hard link) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002943
2944 cifs_buf_release(pSMB);
2945 if (rc == -EAGAIN)
2946 goto createHardLinkRetry;
2947
2948 return rc;
2949}
2950
2951int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002952CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002953 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002954 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002955{
2956 int rc = 0;
2957 NT_RENAME_REQ *pSMB = NULL;
2958 RENAME_RSP *pSMBr = NULL;
2959 int bytes_returned;
2960 int name_len, name_len2;
2961 __u16 count;
2962
Joe Perchesb6b38f72010-04-21 03:50:45 +00002963 cFYI(1, "In CIFSCreateHardLink");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002964winCreateHardLinkRetry:
2965
2966 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2967 (void **) &pSMBr);
2968 if (rc)
2969 return rc;
2970
2971 pSMB->SearchAttributes =
2972 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2973 ATTR_DIRECTORY);
2974 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2975 pSMB->ClusterCount = 0;
2976
2977 pSMB->BufferFormat = 0x04;
2978
2979 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2980 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06002981 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, fromName,
2982 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002983 name_len++; /* trailing null */
2984 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05002985
2986 /* protocol specifies ASCII buffer format (0x04) for unicode */
2987 pSMB->OldFileName[name_len] = 0x04;
2988 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002989 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002990 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2991 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002992 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2993 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002994 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002995 name_len = strnlen(fromName, PATH_MAX);
2996 name_len++; /* trailing null */
2997 strncpy(pSMB->OldFileName, fromName, name_len);
2998 name_len2 = strnlen(toName, PATH_MAX);
2999 name_len2++; /* trailing null */
3000 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
3001 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
3002 name_len2++; /* trailing null */
3003 name_len2++; /* signature byte */
3004 }
3005
3006 count = 1 /* string type byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003007 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003008 pSMB->ByteCount = cpu_to_le16(count);
3009
3010 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3011 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003012 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00003013 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003014 cFYI(1, "Send error in hard link (NT rename) = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00003015
Linus Torvalds1da177e2005-04-16 15:20:36 -07003016 cifs_buf_release(pSMB);
3017 if (rc == -EAGAIN)
3018 goto winCreateHardLinkRetry;
3019
3020 return rc;
3021}
3022
3023int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003024CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04003025 const unsigned char *searchName, char **symlinkinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003026 const struct nls_table *nls_codepage)
3027{
3028/* SMB_QUERY_FILE_UNIX_LINK */
3029 TRANSACTION2_QPI_REQ *pSMB = NULL;
3030 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3031 int rc = 0;
3032 int bytes_returned;
3033 int name_len;
3034 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04003035 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003036
Joe Perchesb6b38f72010-04-21 03:50:45 +00003037 cFYI(1, "In QPathSymLinkInfo (Unix) for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003038
3039querySymLinkRetry:
3040 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3041 (void **) &pSMBr);
3042 if (rc)
3043 return rc;
3044
3045 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3046 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003047 cifs_strtoUTF16((__le16 *) pSMB->FileName, searchName,
3048 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003049 name_len++; /* trailing null */
3050 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003051 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003052 name_len = strnlen(searchName, PATH_MAX);
3053 name_len++; /* trailing null */
3054 strncpy(pSMB->FileName, searchName, name_len);
3055 }
3056
3057 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3058 pSMB->TotalDataCount = 0;
3059 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04003060 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003061 pSMB->MaxSetupCount = 0;
3062 pSMB->Reserved = 0;
3063 pSMB->Flags = 0;
3064 pSMB->Timeout = 0;
3065 pSMB->Reserved2 = 0;
3066 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003067 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003068 pSMB->DataCount = 0;
3069 pSMB->DataOffset = 0;
3070 pSMB->SetupCount = 1;
3071 pSMB->Reserved3 = 0;
3072 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3073 byte_count = params + 1 /* pad */ ;
3074 pSMB->TotalParameterCount = cpu_to_le16(params);
3075 pSMB->ParameterCount = pSMB->TotalParameterCount;
3076 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
3077 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003078 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003079 pSMB->ByteCount = cpu_to_le16(byte_count);
3080
3081 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3082 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3083 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003084 cFYI(1, "Send error in QuerySymLinkInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003085 } else {
3086 /* decode response */
3087
3088 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003089 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003090 if (rc || get_bcc(&pSMBr->hdr) < 2)
Jeff Layton460b9692009-04-30 07:17:56 -04003091 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003092 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00003093 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04003094 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003095
Jeff Layton460b9692009-04-30 07:17:56 -04003096 data_start = ((char *) &pSMBr->hdr.Protocol) +
3097 le16_to_cpu(pSMBr->t2.DataOffset);
3098
Steve French0e0d2cf2009-05-01 05:27:32 +00003099 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3100 is_unicode = true;
3101 else
3102 is_unicode = false;
3103
Steve French737b7582005-04-28 22:41:06 -07003104 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchacbbb762012-01-18 22:32:33 -06003105 *symlinkinfo = cifs_strndup_from_utf16(data_start,
3106 count, is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04003107 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04003108 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003109 }
3110 }
3111 cifs_buf_release(pSMB);
3112 if (rc == -EAGAIN)
3113 goto querySymLinkRetry;
3114 return rc;
3115}
3116
Steve Frenchc52a95542011-02-24 06:16:22 +00003117#ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL
3118/*
3119 * Recent Windows versions now create symlinks more frequently
3120 * and they use the "reparse point" mechanism below. We can of course
3121 * do symlinks nicely to Samba and other servers which support the
3122 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
3123 * "MF" symlinks optionally, but for recent Windows we really need to
3124 * reenable the code below and fix the cifs_symlink callers to handle this.
3125 * In the interim this code has been moved to its own config option so
3126 * it is not compiled in by default until callers fixed up and more tested.
3127 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003128int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003129CIFSSMBQueryReparseLinkInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003130 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00003131 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003132 const struct nls_table *nls_codepage)
3133{
3134 int rc = 0;
3135 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00003136 struct smb_com_transaction_ioctl_req *pSMB;
3137 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003138
Joe Perchesb6b38f72010-04-21 03:50:45 +00003139 cFYI(1, "In Windows reparse style QueryLink for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003140 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3141 (void **) &pSMBr);
3142 if (rc)
3143 return rc;
3144
3145 pSMB->TotalParameterCount = 0 ;
3146 pSMB->TotalDataCount = 0;
3147 pSMB->MaxParameterCount = cpu_to_le32(2);
3148 /* BB find exact data count max from sess structure BB */
Jeff Laytonc974bef2011-10-11 06:41:32 -04003149 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003150 pSMB->MaxSetupCount = 4;
3151 pSMB->Reserved = 0;
3152 pSMB->ParameterOffset = 0;
3153 pSMB->DataCount = 0;
3154 pSMB->DataOffset = 0;
3155 pSMB->SetupCount = 4;
3156 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
3157 pSMB->ParameterCount = pSMB->TotalParameterCount;
3158 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
3159 pSMB->IsFsctl = 1; /* FSCTL */
3160 pSMB->IsRootFlag = 0;
3161 pSMB->Fid = fid; /* file handle always le */
3162 pSMB->ByteCount = 0;
3163
3164 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3165 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3166 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003167 cFYI(1, "Send error in QueryReparseLinkInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003168 } else { /* decode response */
3169 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
3170 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
Jeff Layton820a8032011-05-04 08:05:26 -04003171 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
3172 /* BB also check enough total bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003173 rc = -EIO; /* bad smb */
Steve Frenchafe48c32009-05-02 05:25:46 +00003174 goto qreparse_out;
3175 }
3176 if (data_count && (data_count < 2048)) {
3177 char *end_of_smb = 2 /* sizeof byte count */ +
Jeff Layton820a8032011-05-04 08:05:26 -04003178 get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003179
Steve Frenchafe48c32009-05-02 05:25:46 +00003180 struct reparse_data *reparse_buf =
Steve French50c2f752007-07-13 00:33:32 +00003181 (struct reparse_data *)
3182 ((char *)&pSMBr->hdr.Protocol
3183 + data_offset);
Steve Frenchafe48c32009-05-02 05:25:46 +00003184 if ((char *)reparse_buf >= end_of_smb) {
3185 rc = -EIO;
3186 goto qreparse_out;
3187 }
3188 if ((reparse_buf->LinkNamesBuf +
3189 reparse_buf->TargetNameOffset +
3190 reparse_buf->TargetNameLen) > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003191 cFYI(1, "reparse buf beyond SMB");
Steve Frenchafe48c32009-05-02 05:25:46 +00003192 rc = -EIO;
3193 goto qreparse_out;
3194 }
Steve French50c2f752007-07-13 00:33:32 +00003195
Steve Frenchafe48c32009-05-02 05:25:46 +00003196 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3197 cifs_from_ucs2(symlinkinfo, (__le16 *)
Steve French50c2f752007-07-13 00:33:32 +00003198 (reparse_buf->LinkNamesBuf +
3199 reparse_buf->TargetNameOffset),
Steve Frenchafe48c32009-05-02 05:25:46 +00003200 buflen,
3201 reparse_buf->TargetNameLen,
3202 nls_codepage, 0);
3203 } else { /* ASCII names */
3204 strncpy(symlinkinfo,
3205 reparse_buf->LinkNamesBuf +
3206 reparse_buf->TargetNameOffset,
3207 min_t(const int, buflen,
3208 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003209 }
Steve Frenchafe48c32009-05-02 05:25:46 +00003210 } else {
3211 rc = -EIO;
Joe Perchesb6b38f72010-04-21 03:50:45 +00003212 cFYI(1, "Invalid return data count on "
3213 "get reparse info ioctl");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003214 }
Steve Frenchafe48c32009-05-02 05:25:46 +00003215 symlinkinfo[buflen] = 0; /* just in case so the caller
3216 does not go off the end of the buffer */
Joe Perchesb6b38f72010-04-21 03:50:45 +00003217 cFYI(1, "readlink result - %s", symlinkinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003218 }
Steve French989c7e52009-05-02 05:32:20 +00003219
Linus Torvalds1da177e2005-04-16 15:20:36 -07003220qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07003221 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003222
3223 /* Note: On -EAGAIN error only caller can retry on handle based calls
3224 since file handle passed in no longer valid */
3225
3226 return rc;
3227}
Steve Frenchc52a95542011-02-24 06:16:22 +00003228#endif /* CIFS_SYMLINK_EXPERIMENTAL */ /* BB temporarily unused */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003229
3230#ifdef CONFIG_CIFS_POSIX
3231
3232/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00003233static void cifs_convert_ace(posix_acl_xattr_entry *ace,
3234 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003235{
3236 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08003237 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
3238 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
3239 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesb6b38f72010-04-21 03:50:45 +00003240 /* cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003241
3242 return;
3243}
3244
3245/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00003246static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
3247 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003248{
3249 int size = 0;
3250 int i;
3251 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00003252 struct cifs_posix_ace *pACE;
3253 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
3254 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003255
3256 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
3257 return -EOPNOTSUPP;
3258
Steve French790fe572007-07-07 19:25:05 +00003259 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003260 count = le16_to_cpu(cifs_acl->access_entry_count);
3261 pACE = &cifs_acl->ace_array[0];
3262 size = sizeof(struct cifs_posix_acl);
3263 size += sizeof(struct cifs_posix_ace) * count;
3264 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003265 if (size_of_data_area < size) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003266 cFYI(1, "bad CIFS POSIX ACL size %d vs. %d",
3267 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003268 return -EINVAL;
3269 }
Steve French790fe572007-07-07 19:25:05 +00003270 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003271 count = le16_to_cpu(cifs_acl->access_entry_count);
3272 size = sizeof(struct cifs_posix_acl);
3273 size += sizeof(struct cifs_posix_ace) * count;
3274/* skip past access ACEs to get to default ACEs */
3275 pACE = &cifs_acl->ace_array[count];
3276 count = le16_to_cpu(cifs_acl->default_entry_count);
3277 size += sizeof(struct cifs_posix_ace) * count;
3278 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003279 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003280 return -EINVAL;
3281 } else {
3282 /* illegal type */
3283 return -EINVAL;
3284 }
3285
3286 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00003287 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00003288 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00003289 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003290 return -ERANGE;
3291 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08003292 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00003293 for (i = 0; i < count ; i++) {
3294 cifs_convert_ace(&local_acl->a_entries[i], pACE);
3295 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003296 }
3297 }
3298 return size;
3299}
3300
Steve French50c2f752007-07-13 00:33:32 +00003301static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
3302 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003303{
3304 __u16 rc = 0; /* 0 = ACL converted ok */
3305
Steve Frenchff7feac2005-11-15 16:45:16 -08003306 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
3307 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003308 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00003309 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003310 /* Probably no need to le convert -1 on any arch but can not hurt */
3311 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00003312 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08003313 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesb6b38f72010-04-21 03:50:45 +00003314 /*cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id);*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003315 return rc;
3316}
3317
3318/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00003319static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
3320 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003321{
3322 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00003323 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
3324 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003325 int count;
3326 int i;
3327
Steve French790fe572007-07-07 19:25:05 +00003328 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003329 return 0;
3330
3331 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesb6b38f72010-04-21 03:50:45 +00003332 cFYI(1, "setting acl with %d entries from buf of length %d and "
Steve French63135e02007-07-17 17:34:02 +00003333 "version of %d",
Joe Perchesb6b38f72010-04-21 03:50:45 +00003334 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00003335 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003336 cFYI(1, "unknown POSIX ACL version %d",
3337 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003338 return 0;
3339 }
3340 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00003341 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08003342 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00003343 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08003344 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003345 else {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003346 cFYI(1, "unknown ACL type %d", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003347 return 0;
3348 }
Steve French50c2f752007-07-13 00:33:32 +00003349 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003350 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
3351 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00003352 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003353 /* ACE not converted */
3354 break;
3355 }
3356 }
Steve French790fe572007-07-07 19:25:05 +00003357 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003358 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
3359 rc += sizeof(struct cifs_posix_acl);
3360 /* BB add check to make sure ACL does not overflow SMB */
3361 }
3362 return rc;
3363}
3364
3365int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003366CIFSSMBGetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003367 const unsigned char *searchName,
3368 char *acl_inf, const int buflen, const int acl_type,
3369 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003370{
3371/* SMB_QUERY_POSIX_ACL */
3372 TRANSACTION2_QPI_REQ *pSMB = NULL;
3373 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3374 int rc = 0;
3375 int bytes_returned;
3376 int name_len;
3377 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00003378
Joe Perchesb6b38f72010-04-21 03:50:45 +00003379 cFYI(1, "In GetPosixACL (Unix) for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003380
3381queryAclRetry:
3382 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3383 (void **) &pSMBr);
3384 if (rc)
3385 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003386
Linus Torvalds1da177e2005-04-16 15:20:36 -07003387 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3388 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003389 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3390 searchName, PATH_MAX, nls_codepage,
3391 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003392 name_len++; /* trailing null */
3393 name_len *= 2;
3394 pSMB->FileName[name_len] = 0;
3395 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00003396 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003397 name_len = strnlen(searchName, PATH_MAX);
3398 name_len++; /* trailing null */
3399 strncpy(pSMB->FileName, searchName, name_len);
3400 }
3401
3402 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3403 pSMB->TotalDataCount = 0;
3404 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00003405 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003406 pSMB->MaxDataCount = cpu_to_le16(4000);
3407 pSMB->MaxSetupCount = 0;
3408 pSMB->Reserved = 0;
3409 pSMB->Flags = 0;
3410 pSMB->Timeout = 0;
3411 pSMB->Reserved2 = 0;
3412 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003413 offsetof(struct smb_com_transaction2_qpi_req,
3414 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003415 pSMB->DataCount = 0;
3416 pSMB->DataOffset = 0;
3417 pSMB->SetupCount = 1;
3418 pSMB->Reserved3 = 0;
3419 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3420 byte_count = params + 1 /* pad */ ;
3421 pSMB->TotalParameterCount = cpu_to_le16(params);
3422 pSMB->ParameterCount = pSMB->TotalParameterCount;
3423 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
3424 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003425 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003426 pSMB->ByteCount = cpu_to_le16(byte_count);
3427
3428 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3429 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003430 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003431 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003432 cFYI(1, "Send error in Query POSIX ACL = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003433 } else {
3434 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00003435
Linus Torvalds1da177e2005-04-16 15:20:36 -07003436 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003437 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003438 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003439 rc = -EIO; /* bad smb */
3440 else {
3441 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3442 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3443 rc = cifs_copy_posix_acl(acl_inf,
3444 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00003445 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003446 }
3447 }
3448 cifs_buf_release(pSMB);
3449 if (rc == -EAGAIN)
3450 goto queryAclRetry;
3451 return rc;
3452}
3453
3454int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003455CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003456 const unsigned char *fileName,
3457 const char *local_acl, const int buflen,
3458 const int acl_type,
3459 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003460{
3461 struct smb_com_transaction2_spi_req *pSMB = NULL;
3462 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3463 char *parm_data;
3464 int name_len;
3465 int rc = 0;
3466 int bytes_returned = 0;
3467 __u16 params, byte_count, data_count, param_offset, offset;
3468
Joe Perchesb6b38f72010-04-21 03:50:45 +00003469 cFYI(1, "In SetPosixACL (Unix) for path %s", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003470setAclRetry:
3471 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003472 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003473 if (rc)
3474 return rc;
3475 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3476 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003477 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
3478 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003479 name_len++; /* trailing null */
3480 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003481 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003482 name_len = strnlen(fileName, PATH_MAX);
3483 name_len++; /* trailing null */
3484 strncpy(pSMB->FileName, fileName, name_len);
3485 }
3486 params = 6 + name_len;
3487 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003488 /* BB find max SMB size from sess */
3489 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003490 pSMB->MaxSetupCount = 0;
3491 pSMB->Reserved = 0;
3492 pSMB->Flags = 0;
3493 pSMB->Timeout = 0;
3494 pSMB->Reserved2 = 0;
3495 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003496 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003497 offset = param_offset + params;
3498 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
3499 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3500
3501 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00003502 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003503
Steve French790fe572007-07-07 19:25:05 +00003504 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003505 rc = -EOPNOTSUPP;
3506 goto setACLerrorExit;
3507 }
3508 pSMB->DataOffset = cpu_to_le16(offset);
3509 pSMB->SetupCount = 1;
3510 pSMB->Reserved3 = 0;
3511 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3512 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
3513 byte_count = 3 /* pad */ + params + data_count;
3514 pSMB->DataCount = cpu_to_le16(data_count);
3515 pSMB->TotalDataCount = pSMB->DataCount;
3516 pSMB->ParameterCount = cpu_to_le16(params);
3517 pSMB->TotalParameterCount = pSMB->ParameterCount;
3518 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003519 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003520 pSMB->ByteCount = cpu_to_le16(byte_count);
3521 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003522 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003523 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003524 cFYI(1, "Set POSIX ACL returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003525
3526setACLerrorExit:
3527 cifs_buf_release(pSMB);
3528 if (rc == -EAGAIN)
3529 goto setAclRetry;
3530 return rc;
3531}
3532
Steve Frenchf654bac2005-04-28 22:41:04 -07003533/* BB fix tabs in this function FIXME BB */
3534int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003535CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00003536 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07003537{
Steve French50c2f752007-07-13 00:33:32 +00003538 int rc = 0;
3539 struct smb_t2_qfi_req *pSMB = NULL;
3540 struct smb_t2_qfi_rsp *pSMBr = NULL;
3541 int bytes_returned;
3542 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07003543
Joe Perchesb6b38f72010-04-21 03:50:45 +00003544 cFYI(1, "In GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00003545 if (tcon == NULL)
3546 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07003547
3548GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003549 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3550 (void **) &pSMBr);
3551 if (rc)
3552 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003553
Steve Frenchad7a2922008-02-07 23:25:02 +00003554 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003555 pSMB->t2.TotalDataCount = 0;
3556 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3557 /* BB find exact max data count below from sess structure BB */
3558 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3559 pSMB->t2.MaxSetupCount = 0;
3560 pSMB->t2.Reserved = 0;
3561 pSMB->t2.Flags = 0;
3562 pSMB->t2.Timeout = 0;
3563 pSMB->t2.Reserved2 = 0;
3564 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3565 Fid) - 4);
3566 pSMB->t2.DataCount = 0;
3567 pSMB->t2.DataOffset = 0;
3568 pSMB->t2.SetupCount = 1;
3569 pSMB->t2.Reserved3 = 0;
3570 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3571 byte_count = params + 1 /* pad */ ;
3572 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3573 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3574 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3575 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003576 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003577 inc_rfc1001_len(pSMB, byte_count);
Steve French790fe572007-07-07 19:25:05 +00003578 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003579
Steve French790fe572007-07-07 19:25:05 +00003580 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3581 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3582 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003583 cFYI(1, "error %d in GetExtAttr", rc);
Steve French790fe572007-07-07 19:25:05 +00003584 } else {
3585 /* decode response */
3586 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003587 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003588 if (rc || get_bcc(&pSMBr->hdr) < 2)
Steve French790fe572007-07-07 19:25:05 +00003589 /* If rc should we check for EOPNOSUPP and
3590 disable the srvino flag? or in caller? */
3591 rc = -EIO; /* bad smb */
3592 else {
3593 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3594 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3595 struct file_chattr_info *pfinfo;
3596 /* BB Do we need a cast or hash here ? */
3597 if (count != 16) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003598 cFYI(1, "Illegal size ret in GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00003599 rc = -EIO;
3600 goto GetExtAttrOut;
3601 }
3602 pfinfo = (struct file_chattr_info *)
3603 (data_offset + (char *) &pSMBr->hdr.Protocol);
3604 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003605 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003606 }
3607 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003608GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003609 cifs_buf_release(pSMB);
3610 if (rc == -EAGAIN)
3611 goto GetExtAttrRetry;
3612 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003613}
3614
Steve Frenchf654bac2005-04-28 22:41:04 -07003615#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003616
Jeff Layton79df1ba2010-12-06 12:52:08 -05003617#ifdef CONFIG_CIFS_ACL
3618/*
3619 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3620 * all NT TRANSACTS that we init here have total parm and data under about 400
3621 * bytes (to fit in small cifs buffer size), which is the case so far, it
3622 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3623 * returned setup area) and MaxParameterCount (returned parms size) must be set
3624 * by caller
3625 */
3626static int
3627smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French96daf2b2011-05-27 04:34:02 +00003628 const int parm_len, struct cifs_tcon *tcon,
Jeff Layton79df1ba2010-12-06 12:52:08 -05003629 void **ret_buf)
3630{
3631 int rc;
3632 __u32 temp_offset;
3633 struct smb_com_ntransact_req *pSMB;
3634
3635 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3636 (void **)&pSMB);
3637 if (rc)
3638 return rc;
3639 *ret_buf = (void *)pSMB;
3640 pSMB->Reserved = 0;
3641 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3642 pSMB->TotalDataCount = 0;
Jeff Laytonc974bef2011-10-11 06:41:32 -04003643 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003644 pSMB->ParameterCount = pSMB->TotalParameterCount;
3645 pSMB->DataCount = pSMB->TotalDataCount;
3646 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3647 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3648 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3649 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3650 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3651 pSMB->SubCommand = cpu_to_le16(sub_command);
3652 return 0;
3653}
3654
3655static int
3656validate_ntransact(char *buf, char **ppparm, char **ppdata,
3657 __u32 *pparmlen, __u32 *pdatalen)
3658{
3659 char *end_of_smb;
3660 __u32 data_count, data_offset, parm_count, parm_offset;
3661 struct smb_com_ntransact_rsp *pSMBr;
Jeff Layton820a8032011-05-04 08:05:26 -04003662 u16 bcc;
Jeff Layton79df1ba2010-12-06 12:52:08 -05003663
3664 *pdatalen = 0;
3665 *pparmlen = 0;
3666
3667 if (buf == NULL)
3668 return -EINVAL;
3669
3670 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3671
Jeff Layton820a8032011-05-04 08:05:26 -04003672 bcc = get_bcc(&pSMBr->hdr);
3673 end_of_smb = 2 /* sizeof byte count */ + bcc +
Jeff Layton79df1ba2010-12-06 12:52:08 -05003674 (char *)&pSMBr->ByteCount;
3675
3676 data_offset = le32_to_cpu(pSMBr->DataOffset);
3677 data_count = le32_to_cpu(pSMBr->DataCount);
3678 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3679 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3680
3681 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3682 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3683
3684 /* should we also check that parm and data areas do not overlap? */
3685 if (*ppparm > end_of_smb) {
3686 cFYI(1, "parms start after end of smb");
3687 return -EINVAL;
3688 } else if (parm_count + *ppparm > end_of_smb) {
3689 cFYI(1, "parm end after end of smb");
3690 return -EINVAL;
3691 } else if (*ppdata > end_of_smb) {
3692 cFYI(1, "data starts after end of smb");
3693 return -EINVAL;
3694 } else if (data_count + *ppdata > end_of_smb) {
3695 cFYI(1, "data %p + count %d (%p) past smb end %p start %p",
3696 *ppdata, data_count, (data_count + *ppdata),
3697 end_of_smb, pSMBr);
3698 return -EINVAL;
Jeff Layton820a8032011-05-04 08:05:26 -04003699 } else if (parm_count + data_count > bcc) {
Jeff Layton79df1ba2010-12-06 12:52:08 -05003700 cFYI(1, "parm count and data count larger than SMB");
3701 return -EINVAL;
3702 }
3703 *pdatalen = data_count;
3704 *pparmlen = parm_count;
3705 return 0;
3706}
3707
Steve French0a4b92c2006-01-12 15:44:21 -08003708/* Get Security Descriptor (by handle) from remote server for a file or dir */
3709int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003710CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003711 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003712{
3713 int rc = 0;
3714 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003715 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003716 struct kvec iov[1];
3717
Joe Perchesb6b38f72010-04-21 03:50:45 +00003718 cFYI(1, "GetCifsACL");
Steve French0a4b92c2006-01-12 15:44:21 -08003719
Steve French630f3f0c2007-10-25 21:17:17 +00003720 *pbuflen = 0;
3721 *acl_inf = NULL;
3722
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003723 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003724 8 /* parm len */, tcon, (void **) &pSMB);
3725 if (rc)
3726 return rc;
3727
3728 pSMB->MaxParameterCount = cpu_to_le32(4);
3729 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3730 pSMB->MaxSetupCount = 0;
3731 pSMB->Fid = fid; /* file handle always le */
3732 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3733 CIFS_ACL_DACL);
3734 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003735 inc_rfc1001_len(pSMB, 11);
Steve French0a4b92c2006-01-12 15:44:21 -08003736 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003737 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French0a4b92c2006-01-12 15:44:21 -08003738
Steve Frencha761ac52007-10-18 21:45:27 +00003739 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Jeff Layton77499812011-01-11 07:24:23 -05003740 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003741 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Steve French0a4b92c2006-01-12 15:44:21 -08003742 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003743 cFYI(1, "Send error in QuerySecDesc = %d", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08003744 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003745 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003746 __u32 parm_len;
3747 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003748 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003749 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003750
3751/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003752 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003753 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003754 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003755 goto qsec_out;
3756 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3757
Joe Perchesb6b38f72010-04-21 03:50:45 +00003758 cFYI(1, "smb %p parm %p data %p", pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08003759
3760 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3761 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003762 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003763 goto qsec_out;
3764 }
3765
3766/* BB check that data area is minimum length and as big as acl_len */
3767
Steve Frenchaf6f4612007-10-16 18:40:37 +00003768 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003769 if (acl_len != *pbuflen) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003770 cERROR(1, "acl length %d does not match %d",
3771 acl_len, *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003772 if (*pbuflen > acl_len)
3773 *pbuflen = acl_len;
3774 }
Steve French0a4b92c2006-01-12 15:44:21 -08003775
Steve French630f3f0c2007-10-25 21:17:17 +00003776 /* check if buffer is big enough for the acl
3777 header followed by the smallest SID */
3778 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3779 (*pbuflen >= 64 * 1024)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003780 cERROR(1, "bad acl length %d", *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003781 rc = -EINVAL;
3782 *pbuflen = 0;
3783 } else {
3784 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3785 if (*acl_inf == NULL) {
3786 *pbuflen = 0;
3787 rc = -ENOMEM;
3788 }
3789 memcpy(*acl_inf, pdata, *pbuflen);
3790 }
Steve French0a4b92c2006-01-12 15:44:21 -08003791 }
3792qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003793 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003794 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003795 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003796 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003797/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003798 return rc;
3799}
Steve French97837582007-12-31 07:47:21 +00003800
3801int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003802CIFSSMBSetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003803 struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
Steve French97837582007-12-31 07:47:21 +00003804{
3805 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3806 int rc = 0;
3807 int bytes_returned = 0;
3808 SET_SEC_DESC_REQ *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003809 void *pSMBr;
Steve French97837582007-12-31 07:47:21 +00003810
3811setCifsAclRetry:
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003812 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, &pSMBr);
Steve French97837582007-12-31 07:47:21 +00003813 if (rc)
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003814 return rc;
Steve French97837582007-12-31 07:47:21 +00003815
3816 pSMB->MaxSetupCount = 0;
3817 pSMB->Reserved = 0;
3818
3819 param_count = 8;
3820 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3821 data_count = acllen;
3822 data_offset = param_offset + param_count;
3823 byte_count = 3 /* pad */ + param_count;
3824
3825 pSMB->DataCount = cpu_to_le32(data_count);
3826 pSMB->TotalDataCount = pSMB->DataCount;
3827 pSMB->MaxParameterCount = cpu_to_le32(4);
3828 pSMB->MaxDataCount = cpu_to_le32(16384);
3829 pSMB->ParameterCount = cpu_to_le32(param_count);
3830 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3831 pSMB->TotalParameterCount = pSMB->ParameterCount;
3832 pSMB->DataOffset = cpu_to_le32(data_offset);
3833 pSMB->SetupCount = 0;
3834 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3835 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3836
3837 pSMB->Fid = fid; /* file handle always le */
3838 pSMB->Reserved2 = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003839 pSMB->AclFlags = cpu_to_le32(aclflag);
Steve French97837582007-12-31 07:47:21 +00003840
3841 if (pntsd && acllen) {
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003842 memcpy((char *)pSMBr + offsetof(struct smb_hdr, Protocol) +
3843 data_offset, pntsd, acllen);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003844 inc_rfc1001_len(pSMB, byte_count + data_count);
Steve French97837582007-12-31 07:47:21 +00003845 } else
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003846 inc_rfc1001_len(pSMB, byte_count);
Steve French97837582007-12-31 07:47:21 +00003847
3848 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3849 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3850
Joe Perchesb6b38f72010-04-21 03:50:45 +00003851 cFYI(1, "SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00003852 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003853 cFYI(1, "Set CIFS ACL returned %d", rc);
Steve French97837582007-12-31 07:47:21 +00003854 cifs_buf_release(pSMB);
3855
3856 if (rc == -EAGAIN)
3857 goto setCifsAclRetry;
3858
3859 return (rc);
3860}
3861
Jeff Layton79df1ba2010-12-06 12:52:08 -05003862#endif /* CONFIG_CIFS_ACL */
Steve French0a4b92c2006-01-12 15:44:21 -08003863
Steve French6b8edfe2005-08-23 20:26:03 -07003864/* Legacy Query Path Information call for lookup to old servers such
3865 as Win9x/WinME */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003866int
3867SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon,
3868 const char *search_name, FILE_ALL_INFO *data,
3869 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003870{
Steve Frenchad7a2922008-02-07 23:25:02 +00003871 QUERY_INFORMATION_REQ *pSMB;
3872 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003873 int rc = 0;
3874 int bytes_returned;
3875 int name_len;
3876
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003877 cFYI(1, "In SMBQPath path %s", search_name);
Steve French6b8edfe2005-08-23 20:26:03 -07003878QInfRetry:
3879 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003880 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003881 if (rc)
3882 return rc;
3883
3884 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3885 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003886 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003887 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06003888 remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003889 name_len++; /* trailing null */
3890 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003891 } else {
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003892 name_len = strnlen(search_name, PATH_MAX);
Steve French6b8edfe2005-08-23 20:26:03 -07003893 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003894 strncpy(pSMB->FileName, search_name, name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07003895 }
3896 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003897 name_len++; /* account for buffer type byte */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003898 inc_rfc1001_len(pSMB, (__u16)name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07003899 pSMB->ByteCount = cpu_to_le16(name_len);
3900
3901 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003902 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003903 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003904 cFYI(1, "Send error in QueryInfo = %d", rc);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003905 } else if (data) {
Steve French1bd5bbc2006-09-28 03:35:57 +00003906 struct timespec ts;
3907 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00003908
3909 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003910 /* BB FIXME - add time zone adjustment BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003911 memset(data, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003912 ts.tv_nsec = 0;
3913 ts.tv_sec = time;
3914 /* decode time fields */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003915 data->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
3916 data->LastWriteTime = data->ChangeTime;
3917 data->LastAccessTime = 0;
3918 data->AllocationSize =
Steve French70ca7342005-09-22 16:32:06 -07003919 cpu_to_le64(le32_to_cpu(pSMBr->size));
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003920 data->EndOfFile = data->AllocationSize;
3921 data->Attributes =
Steve French70ca7342005-09-22 16:32:06 -07003922 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003923 } else
3924 rc = -EIO; /* bad buffer passed in */
3925
3926 cifs_buf_release(pSMB);
3927
3928 if (rc == -EAGAIN)
3929 goto QInfRetry;
3930
3931 return rc;
3932}
3933
Jeff Laytonbcd53572010-02-12 07:44:16 -05003934int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003935CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonbcd53572010-02-12 07:44:16 -05003936 u16 netfid, FILE_ALL_INFO *pFindData)
3937{
3938 struct smb_t2_qfi_req *pSMB = NULL;
3939 struct smb_t2_qfi_rsp *pSMBr = NULL;
3940 int rc = 0;
3941 int bytes_returned;
3942 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07003943
Jeff Laytonbcd53572010-02-12 07:44:16 -05003944QFileInfoRetry:
3945 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3946 (void **) &pSMBr);
3947 if (rc)
3948 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07003949
Jeff Laytonbcd53572010-02-12 07:44:16 -05003950 params = 2 /* level */ + 2 /* fid */;
3951 pSMB->t2.TotalDataCount = 0;
3952 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3953 /* BB find exact max data count below from sess structure BB */
3954 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3955 pSMB->t2.MaxSetupCount = 0;
3956 pSMB->t2.Reserved = 0;
3957 pSMB->t2.Flags = 0;
3958 pSMB->t2.Timeout = 0;
3959 pSMB->t2.Reserved2 = 0;
3960 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3961 Fid) - 4);
3962 pSMB->t2.DataCount = 0;
3963 pSMB->t2.DataOffset = 0;
3964 pSMB->t2.SetupCount = 1;
3965 pSMB->t2.Reserved3 = 0;
3966 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3967 byte_count = params + 1 /* pad */ ;
3968 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3969 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3970 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3971 pSMB->Pad = 0;
3972 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003973 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003974
3975 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3976 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3977 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00003978 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003979 } else { /* decode response */
3980 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3981
3982 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3983 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04003984 else if (get_bcc(&pSMBr->hdr) < 40)
Jeff Laytonbcd53572010-02-12 07:44:16 -05003985 rc = -EIO; /* bad smb */
3986 else if (pFindData) {
3987 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3988 memcpy((char *) pFindData,
3989 (char *) &pSMBr->hdr.Protocol +
3990 data_offset, sizeof(FILE_ALL_INFO));
3991 } else
3992 rc = -ENOMEM;
3993 }
3994 cifs_buf_release(pSMB);
3995 if (rc == -EAGAIN)
3996 goto QFileInfoRetry;
3997
3998 return rc;
3999}
Steve French6b8edfe2005-08-23 20:26:03 -07004000
Linus Torvalds1da177e2005-04-16 15:20:36 -07004001int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004002CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004003 const char *search_name, FILE_ALL_INFO *data,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004004 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07004005 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004006{
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004007 /* level 263 SMB_QUERY_FILE_ALL_INFO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004008 TRANSACTION2_QPI_REQ *pSMB = NULL;
4009 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4010 int rc = 0;
4011 int bytes_returned;
4012 int name_len;
4013 __u16 params, byte_count;
4014
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004015 /* cFYI(1, "In QPathInfo path %s", search_name); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004016QPathInfoRetry:
4017 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4018 (void **) &pSMBr);
4019 if (rc)
4020 return rc;
4021
4022 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4023 name_len =
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004024 cifsConvertToUTF16((__le16 *) pSMB->FileName, search_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06004025 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004026 name_len++; /* trailing null */
4027 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004028 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004029 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004030 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004031 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004032 }
4033
Steve French50c2f752007-07-13 00:33:32 +00004034 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004035 pSMB->TotalDataCount = 0;
4036 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004037 /* BB find exact max SMB PDU from sess structure BB */
4038 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004039 pSMB->MaxSetupCount = 0;
4040 pSMB->Reserved = 0;
4041 pSMB->Flags = 0;
4042 pSMB->Timeout = 0;
4043 pSMB->Reserved2 = 0;
4044 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004045 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004046 pSMB->DataCount = 0;
4047 pSMB->DataOffset = 0;
4048 pSMB->SetupCount = 1;
4049 pSMB->Reserved3 = 0;
4050 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4051 byte_count = params + 1 /* pad */ ;
4052 pSMB->TotalParameterCount = cpu_to_le16(params);
4053 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00004054 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004055 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
4056 else
4057 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004058 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004059 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004060 pSMB->ByteCount = cpu_to_le16(byte_count);
4061
4062 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4063 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4064 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004065 cFYI(1, "Send error in QPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004066 } else { /* decode response */
4067 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4068
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004069 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4070 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004071 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004072 rc = -EIO; /* bad smb */
Jeff Layton820a8032011-05-04 08:05:26 -04004073 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
Steve French50c2f752007-07-13 00:33:32 +00004074 rc = -EIO; /* 24 or 26 expected but we do not read
4075 last field */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004076 else if (data) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004077 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004078 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00004079
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004080 /*
4081 * On legacy responses we do not read the last field,
4082 * EAsize, fortunately since it varies by subdialect and
4083 * also note it differs on Set vs Get, ie two bytes or 4
4084 * bytes depending but we don't care here.
4085 */
Steve Frenchad7a2922008-02-07 23:25:02 +00004086 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004087 size = sizeof(FILE_INFO_STANDARD);
4088 else
4089 size = sizeof(FILE_ALL_INFO);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004090 memcpy((char *) data, (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004091 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004092 } else
4093 rc = -ENOMEM;
4094 }
4095 cifs_buf_release(pSMB);
4096 if (rc == -EAGAIN)
4097 goto QPathInfoRetry;
4098
4099 return rc;
4100}
4101
4102int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004103CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004104 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
4105{
4106 struct smb_t2_qfi_req *pSMB = NULL;
4107 struct smb_t2_qfi_rsp *pSMBr = NULL;
4108 int rc = 0;
4109 int bytes_returned;
4110 __u16 params, byte_count;
4111
4112UnixQFileInfoRetry:
4113 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4114 (void **) &pSMBr);
4115 if (rc)
4116 return rc;
4117
4118 params = 2 /* level */ + 2 /* fid */;
4119 pSMB->t2.TotalDataCount = 0;
4120 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4121 /* BB find exact max data count below from sess structure BB */
4122 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4123 pSMB->t2.MaxSetupCount = 0;
4124 pSMB->t2.Reserved = 0;
4125 pSMB->t2.Flags = 0;
4126 pSMB->t2.Timeout = 0;
4127 pSMB->t2.Reserved2 = 0;
4128 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4129 Fid) - 4);
4130 pSMB->t2.DataCount = 0;
4131 pSMB->t2.DataOffset = 0;
4132 pSMB->t2.SetupCount = 1;
4133 pSMB->t2.Reserved3 = 0;
4134 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4135 byte_count = params + 1 /* pad */ ;
4136 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4137 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4138 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4139 pSMB->Pad = 0;
4140 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004141 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004142
4143 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4144 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4145 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00004146 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004147 } else { /* decode response */
4148 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4149
Jeff Layton820a8032011-05-04 08:05:26 -04004150 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004151 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response. "
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004152 "Unix Extensions can be disabled on mount "
Steve Frenchf19159d2010-04-21 04:12:10 +00004153 "by specifying the nosfu mount option.");
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004154 rc = -EIO; /* bad smb */
4155 } else {
4156 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4157 memcpy((char *) pFindData,
4158 (char *) &pSMBr->hdr.Protocol +
4159 data_offset,
4160 sizeof(FILE_UNIX_BASIC_INFO));
4161 }
4162 }
4163
4164 cifs_buf_release(pSMB);
4165 if (rc == -EAGAIN)
4166 goto UnixQFileInfoRetry;
4167
4168 return rc;
4169}
4170
4171int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004172CIFSSMBUnixQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004173 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00004174 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07004175 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004176{
4177/* SMB_QUERY_FILE_UNIX_BASIC */
4178 TRANSACTION2_QPI_REQ *pSMB = NULL;
4179 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4180 int rc = 0;
4181 int bytes_returned = 0;
4182 int name_len;
4183 __u16 params, byte_count;
4184
Joe Perchesb6b38f72010-04-21 03:50:45 +00004185 cFYI(1, "In QPathInfo (Unix) the path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004186UnixQPathInfoRetry:
4187 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4188 (void **) &pSMBr);
4189 if (rc)
4190 return rc;
4191
4192 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4193 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004194 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4195 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004196 name_len++; /* trailing null */
4197 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004198 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004199 name_len = strnlen(searchName, PATH_MAX);
4200 name_len++; /* trailing null */
4201 strncpy(pSMB->FileName, searchName, name_len);
4202 }
4203
Steve French50c2f752007-07-13 00:33:32 +00004204 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004205 pSMB->TotalDataCount = 0;
4206 pSMB->MaxParameterCount = cpu_to_le16(2);
4207 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00004208 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004209 pSMB->MaxSetupCount = 0;
4210 pSMB->Reserved = 0;
4211 pSMB->Flags = 0;
4212 pSMB->Timeout = 0;
4213 pSMB->Reserved2 = 0;
4214 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004215 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004216 pSMB->DataCount = 0;
4217 pSMB->DataOffset = 0;
4218 pSMB->SetupCount = 1;
4219 pSMB->Reserved3 = 0;
4220 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4221 byte_count = params + 1 /* pad */ ;
4222 pSMB->TotalParameterCount = cpu_to_le16(params);
4223 pSMB->ParameterCount = pSMB->TotalParameterCount;
4224 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4225 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004226 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004227 pSMB->ByteCount = cpu_to_le16(byte_count);
4228
4229 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4230 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4231 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004232 cFYI(1, "Send error in QPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004233 } else { /* decode response */
4234 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4235
Jeff Layton820a8032011-05-04 08:05:26 -04004236 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004237 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response. "
Steve French1e71f252007-09-20 15:30:07 +00004238 "Unix Extensions can be disabled on mount "
Joe Perchesb6b38f72010-04-21 03:50:45 +00004239 "by specifying the nosfu mount option.");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004240 rc = -EIO; /* bad smb */
4241 } else {
4242 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4243 memcpy((char *) pFindData,
4244 (char *) &pSMBr->hdr.Protocol +
4245 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00004246 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004247 }
4248 }
4249 cifs_buf_release(pSMB);
4250 if (rc == -EAGAIN)
4251 goto UnixQPathInfoRetry;
4252
4253 return rc;
4254}
4255
Linus Torvalds1da177e2005-04-16 15:20:36 -07004256/* xid, tcon, searchName and codepage are input parms, rest are returned */
4257int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004258CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004259 const char *searchName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004260 const struct nls_table *nls_codepage,
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004261 __u16 *pnetfid, __u16 search_flags,
Steve French50c2f752007-07-13 00:33:32 +00004262 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004263{
4264/* level 257 SMB_ */
4265 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
4266 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004267 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004268 int rc = 0;
4269 int bytes_returned = 0;
4270 int name_len;
4271 __u16 params, byte_count;
4272
Joe Perchesb6b38f72010-04-21 03:50:45 +00004273 cFYI(1, "In FindFirst for %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004274
4275findFirstRetry:
4276 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4277 (void **) &pSMBr);
4278 if (rc)
4279 return rc;
4280
4281 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4282 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004283 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4284 PATH_MAX, nls_codepage, remap);
Steve French737b7582005-04-28 22:41:06 -07004285 /* We can not add the asterik earlier in case
4286 it got remapped to 0xF03A as if it were part of the
4287 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004288 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07004289 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07004290 pSMB->FileName[name_len+1] = 0;
4291 pSMB->FileName[name_len+2] = '*';
4292 pSMB->FileName[name_len+3] = 0;
4293 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004294 pSMB->FileName[name_len] = 0; /* null terminate just in case */
4295 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07004296 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004297 } else { /* BB add check for overrun of SMB buf BB */
4298 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004299/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00004300 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004301 free buffer exit; BB */
4302 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07004303 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07004304 pSMB->FileName[name_len+1] = '*';
4305 pSMB->FileName[name_len+2] = 0;
4306 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004307 }
4308
4309 params = 12 + name_len /* includes null */ ;
4310 pSMB->TotalDataCount = 0; /* no EAs */
4311 pSMB->MaxParameterCount = cpu_to_le16(10);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004312 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004313 pSMB->MaxSetupCount = 0;
4314 pSMB->Reserved = 0;
4315 pSMB->Flags = 0;
4316 pSMB->Timeout = 0;
4317 pSMB->Reserved2 = 0;
4318 byte_count = params + 1 /* pad */ ;
4319 pSMB->TotalParameterCount = cpu_to_le16(params);
4320 pSMB->ParameterCount = pSMB->TotalParameterCount;
4321 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00004322 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
4323 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004324 pSMB->DataCount = 0;
4325 pSMB->DataOffset = 0;
4326 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
4327 pSMB->Reserved3 = 0;
4328 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
4329 pSMB->SearchAttributes =
4330 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
4331 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00004332 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004333 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004334 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4335
4336 /* BB what should we set StorageType to? Does it matter? BB */
4337 pSMB->SearchStorageType = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004338 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004339 pSMB->ByteCount = cpu_to_le16(byte_count);
4340
4341 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4342 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004343 cifs_stats_inc(&tcon->stats.cifs_stats.num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004344
Steve French88274812006-03-09 22:21:45 +00004345 if (rc) {/* BB add logic to retry regular search if Unix search
4346 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004347 /* BB Add code to handle unsupported level rc */
Joe Perchesb6b38f72010-04-21 03:50:45 +00004348 cFYI(1, "Error in FindFirst = %d", rc);
Steve French1982c342005-08-17 12:38:22 -07004349
Steve French88274812006-03-09 22:21:45 +00004350 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004351
4352 /* BB eventually could optimize out free and realloc of buf */
4353 /* for this case */
4354 if (rc == -EAGAIN)
4355 goto findFirstRetry;
4356 } else { /* decode response */
4357 /* BB remember to free buffer if error BB */
4358 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00004359 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004360 unsigned int lnoff;
4361
Linus Torvalds1da177e2005-04-16 15:20:36 -07004362 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004363 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004364 else
Steve French4b18f2a2008-04-29 00:06:05 +00004365 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004366
4367 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004368 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00004369 psrch_inf->srch_entries_start =
4370 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004371 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004372 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
4373 le16_to_cpu(pSMBr->t2.ParameterOffset));
4374
Steve French790fe572007-07-07 19:25:05 +00004375 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004376 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004377 else
Steve French4b18f2a2008-04-29 00:06:05 +00004378 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004379
Steve French50c2f752007-07-13 00:33:32 +00004380 psrch_inf->entries_in_buffer =
4381 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00004382 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004383 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004384 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004385 if (CIFSMaxBufSize < lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004386 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00004387 psrch_inf->last_entry = NULL;
4388 return rc;
4389 }
4390
Steve French0752f152008-10-07 20:03:33 +00004391 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00004392 lnoff;
4393
Linus Torvalds1da177e2005-04-16 15:20:36 -07004394 *pnetfid = parms->SearchHandle;
4395 } else {
4396 cifs_buf_release(pSMB);
4397 }
4398 }
4399
4400 return rc;
4401}
4402
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004403int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
4404 __u16 searchHandle, __u16 search_flags,
4405 struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004406{
4407 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
4408 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004409 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004410 char *response_data;
4411 int rc = 0;
Jeff Layton9438fab2011-08-23 07:21:28 -04004412 int bytes_returned;
4413 unsigned int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004414 __u16 params, byte_count;
4415
Joe Perchesb6b38f72010-04-21 03:50:45 +00004416 cFYI(1, "In FindNext");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004417
Steve French4b18f2a2008-04-29 00:06:05 +00004418 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004419 return -ENOENT;
4420
4421 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4422 (void **) &pSMBr);
4423 if (rc)
4424 return rc;
4425
Steve French50c2f752007-07-13 00:33:32 +00004426 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004427 byte_count = 0;
4428 pSMB->TotalDataCount = 0; /* no EAs */
4429 pSMB->MaxParameterCount = cpu_to_le16(8);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004430 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004431 pSMB->MaxSetupCount = 0;
4432 pSMB->Reserved = 0;
4433 pSMB->Flags = 0;
4434 pSMB->Timeout = 0;
4435 pSMB->Reserved2 = 0;
4436 pSMB->ParameterOffset = cpu_to_le16(
4437 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
4438 pSMB->DataCount = 0;
4439 pSMB->DataOffset = 0;
4440 pSMB->SetupCount = 1;
4441 pSMB->Reserved3 = 0;
4442 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
4443 pSMB->SearchHandle = searchHandle; /* always kept as le */
4444 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00004445 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004446 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4447 pSMB->ResumeKey = psrch_inf->resume_key;
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004448 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004449
4450 name_len = psrch_inf->resume_name_len;
4451 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00004452 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004453 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
4454 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07004455 /* 14 byte parm len above enough for 2 byte null terminator */
4456 pSMB->ResumeFileName[name_len] = 0;
4457 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004458 } else {
4459 rc = -EINVAL;
4460 goto FNext2_err_exit;
4461 }
4462 byte_count = params + 1 /* pad */ ;
4463 pSMB->TotalParameterCount = cpu_to_le16(params);
4464 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004465 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004466 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004467
Linus Torvalds1da177e2005-04-16 15:20:36 -07004468 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4469 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004470 cifs_stats_inc(&tcon->stats.cifs_stats.num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004471 if (rc) {
4472 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00004473 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07004474 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00004475 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004476 } else
Joe Perchesb6b38f72010-04-21 03:50:45 +00004477 cFYI(1, "FindNext returned = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004478 } else { /* decode response */
4479 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00004480
Steve French790fe572007-07-07 19:25:05 +00004481 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004482 unsigned int lnoff;
4483
Linus Torvalds1da177e2005-04-16 15:20:36 -07004484 /* BB fixme add lock for file (srch_info) struct here */
4485 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004486 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004487 else
Steve French4b18f2a2008-04-29 00:06:05 +00004488 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004489 response_data = (char *) &pSMBr->hdr.Protocol +
4490 le16_to_cpu(pSMBr->t2.ParameterOffset);
4491 parms = (T2_FNEXT_RSP_PARMS *)response_data;
4492 response_data = (char *)&pSMBr->hdr.Protocol +
4493 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00004494 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00004495 cifs_small_buf_release(
4496 psrch_inf->ntwrk_buf_start);
4497 else
4498 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004499 psrch_inf->srch_entries_start = response_data;
4500 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004501 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00004502 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004503 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004504 else
Steve French4b18f2a2008-04-29 00:06:05 +00004505 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00004506 psrch_inf->entries_in_buffer =
4507 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004508 psrch_inf->index_of_last_entry +=
4509 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004510 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004511 if (CIFSMaxBufSize < lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004512 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00004513 psrch_inf->last_entry = NULL;
4514 return rc;
4515 } else
4516 psrch_inf->last_entry =
4517 psrch_inf->srch_entries_start + lnoff;
4518
Joe Perchesb6b38f72010-04-21 03:50:45 +00004519/* cFYI(1, "fnxt2 entries in buf %d index_of_last %d",
4520 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004521
4522 /* BB fixme add unlock here */
4523 }
4524
4525 }
4526
4527 /* BB On error, should we leave previous search buf (and count and
4528 last entry fields) intact or free the previous one? */
4529
4530 /* Note: On -EAGAIN error only caller can retry on handle based calls
4531 since file handle passed in no longer valid */
4532FNext2_err_exit:
4533 if (rc != 0)
4534 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004535 return rc;
4536}
4537
4538int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004539CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004540 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004541{
4542 int rc = 0;
4543 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004544
Joe Perchesb6b38f72010-04-21 03:50:45 +00004545 cFYI(1, "In CIFSSMBFindClose");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004546 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
4547
4548 /* no sense returning error if session restarted
4549 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00004550 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004551 return 0;
4552 if (rc)
4553 return rc;
4554
Linus Torvalds1da177e2005-04-16 15:20:36 -07004555 pSMB->FileID = searchHandle;
4556 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04004557 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004558 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00004559 cERROR(1, "Send error in FindClose = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00004560
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004561 cifs_stats_inc(&tcon->stats.cifs_stats.num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004562
4563 /* Since session is dead, search handle closed on server already */
4564 if (rc == -EAGAIN)
4565 rc = 0;
4566
4567 return rc;
4568}
4569
Linus Torvalds1da177e2005-04-16 15:20:36 -07004570int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004571CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004572 const char *search_name, __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00004573 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004574{
4575 int rc = 0;
4576 TRANSACTION2_QPI_REQ *pSMB = NULL;
4577 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4578 int name_len, bytes_returned;
4579 __u16 params, byte_count;
4580
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004581 cFYI(1, "In GetSrvInodeNum for %s", search_name);
Steve French790fe572007-07-07 19:25:05 +00004582 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00004583 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004584
4585GetInodeNumberRetry:
4586 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004587 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004588 if (rc)
4589 return rc;
4590
Linus Torvalds1da177e2005-04-16 15:20:36 -07004591 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4592 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004593 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004594 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004595 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004596 name_len++; /* trailing null */
4597 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004598 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004599 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004600 name_len++; /* trailing null */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004601 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004602 }
4603
4604 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4605 pSMB->TotalDataCount = 0;
4606 pSMB->MaxParameterCount = cpu_to_le16(2);
4607 /* BB find exact max data count below from sess structure BB */
4608 pSMB->MaxDataCount = cpu_to_le16(4000);
4609 pSMB->MaxSetupCount = 0;
4610 pSMB->Reserved = 0;
4611 pSMB->Flags = 0;
4612 pSMB->Timeout = 0;
4613 pSMB->Reserved2 = 0;
4614 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004615 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004616 pSMB->DataCount = 0;
4617 pSMB->DataOffset = 0;
4618 pSMB->SetupCount = 1;
4619 pSMB->Reserved3 = 0;
4620 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4621 byte_count = params + 1 /* pad */ ;
4622 pSMB->TotalParameterCount = cpu_to_le16(params);
4623 pSMB->ParameterCount = pSMB->TotalParameterCount;
4624 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4625 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004626 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004627 pSMB->ByteCount = cpu_to_le16(byte_count);
4628
4629 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4630 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4631 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004632 cFYI(1, "error %d in QueryInternalInfo", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004633 } else {
4634 /* decode response */
4635 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004636 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04004637 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004638 /* If rc should we check for EOPNOSUPP and
4639 disable the srvino flag? or in caller? */
4640 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00004641 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004642 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4643 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00004644 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004645 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00004646 if (count < 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004647 cFYI(1, "Illegal size ret in QryIntrnlInf");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004648 rc = -EIO;
4649 goto GetInodeNumOut;
4650 }
4651 pfinfo = (struct file_internal_info *)
4652 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00004653 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004654 }
4655 }
4656GetInodeNumOut:
4657 cifs_buf_release(pSMB);
4658 if (rc == -EAGAIN)
4659 goto GetInodeNumberRetry;
4660 return rc;
4661}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004662
Igor Mammedovfec45852008-05-16 13:06:30 +04004663/* parses DFS refferal V3 structure
4664 * caller is responsible for freeing target_nodes
4665 * returns:
4666 * on success - 0
4667 * on failure - errno
4668 */
4669static int
Steve Frencha1fe78f2008-05-16 18:48:38 +00004670parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
Igor Mammedovfec45852008-05-16 13:06:30 +04004671 unsigned int *num_of_nodes,
4672 struct dfs_info3_param **target_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004673 const struct nls_table *nls_codepage, int remap,
4674 const char *searchName)
Igor Mammedovfec45852008-05-16 13:06:30 +04004675{
4676 int i, rc = 0;
4677 char *data_end;
4678 bool is_unicode;
4679 struct dfs_referral_level_3 *ref;
4680
Harvey Harrison5ca33c62008-07-23 17:45:58 -07004681 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4682 is_unicode = true;
4683 else
4684 is_unicode = false;
Igor Mammedovfec45852008-05-16 13:06:30 +04004685 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
4686
4687 if (*num_of_nodes < 1) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004688 cERROR(1, "num_referrals: must be at least > 0,"
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004689 "but we get num_referrals = %d", *num_of_nodes);
Igor Mammedovfec45852008-05-16 13:06:30 +04004690 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004691 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004692 }
4693
4694 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
Al Viro1d92cfd2008-06-02 10:59:02 +01004695 if (ref->VersionNumber != cpu_to_le16(3)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004696 cERROR(1, "Referrals of V%d version are not supported,"
4697 "should be V3", le16_to_cpu(ref->VersionNumber));
Igor Mammedovfec45852008-05-16 13:06:30 +04004698 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004699 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004700 }
4701
4702 /* get the upper boundary of the resp buffer */
4703 data_end = (char *)(&(pSMBr->PathConsumed)) +
4704 le16_to_cpu(pSMBr->t2.DataCount);
4705
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004706 cFYI(1, "num_referrals: %d dfs flags: 0x%x ...",
Igor Mammedovfec45852008-05-16 13:06:30 +04004707 *num_of_nodes,
Joe Perchesb6b38f72010-04-21 03:50:45 +00004708 le32_to_cpu(pSMBr->DFSFlags));
Igor Mammedovfec45852008-05-16 13:06:30 +04004709
4710 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
4711 *num_of_nodes, GFP_KERNEL);
4712 if (*target_nodes == NULL) {
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04004713 cERROR(1, "Failed to allocate buffer for target_nodes");
Igor Mammedovfec45852008-05-16 13:06:30 +04004714 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004715 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004716 }
4717
Daniel Mack3ad2f3fb2010-02-03 08:01:28 +08004718 /* collect necessary data from referrals */
Igor Mammedovfec45852008-05-16 13:06:30 +04004719 for (i = 0; i < *num_of_nodes; i++) {
4720 char *temp;
4721 int max_len;
4722 struct dfs_info3_param *node = (*target_nodes)+i;
4723
Steve French0e0d2cf2009-05-01 05:27:32 +00004724 node->flags = le32_to_cpu(pSMBr->DFSFlags);
Igor Mammedov2c556082008-10-23 13:58:42 +04004725 if (is_unicode) {
Jeff Layton331c3132008-12-17 06:31:53 -05004726 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4727 GFP_KERNEL);
Steve French2920ee22009-08-31 15:27:26 +00004728 if (tmp == NULL) {
4729 rc = -ENOMEM;
4730 goto parse_DFS_referrals_exit;
4731 }
Steve Frenchacbbb762012-01-18 22:32:33 -06004732 cifsConvertToUTF16((__le16 *) tmp, searchName,
4733 PATH_MAX, nls_codepage, remap);
4734 node->path_consumed = cifs_utf16_bytes(tmp,
Jeff Layton69f801f2009-04-30 06:46:32 -04004735 le16_to_cpu(pSMBr->PathConsumed),
Igor Mammedov2c556082008-10-23 13:58:42 +04004736 nls_codepage);
4737 kfree(tmp);
4738 } else
4739 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4740
Igor Mammedovfec45852008-05-16 13:06:30 +04004741 node->server_type = le16_to_cpu(ref->ServerType);
4742 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4743
4744 /* copy DfsPath */
4745 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4746 max_len = data_end - temp;
Steve Frenchacbbb762012-01-18 22:32:33 -06004747 node->path_name = cifs_strndup_from_utf16(temp, max_len,
4748 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004749 if (!node->path_name) {
4750 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004751 goto parse_DFS_referrals_exit;
Jeff Layton066ce682009-04-30 07:16:14 -04004752 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004753
4754 /* copy link target UNC */
4755 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4756 max_len = data_end - temp;
Steve Frenchacbbb762012-01-18 22:32:33 -06004757 node->node_name = cifs_strndup_from_utf16(temp, max_len,
4758 is_unicode, nls_codepage);
Stefan Metzmacherd8f27992012-05-04 00:19:28 +02004759 if (!node->node_name) {
Jeff Laytond8e2f532009-05-14 07:46:59 -04004760 rc = -ENOMEM;
Stefan Metzmacherd8f27992012-05-04 00:19:28 +02004761 goto parse_DFS_referrals_exit;
4762 }
4763
4764 ref++;
Igor Mammedovfec45852008-05-16 13:06:30 +04004765 }
4766
Steve Frencha1fe78f2008-05-16 18:48:38 +00004767parse_DFS_referrals_exit:
Igor Mammedovfec45852008-05-16 13:06:30 +04004768 if (rc) {
4769 free_dfs_info_array(*target_nodes, *num_of_nodes);
4770 *target_nodes = NULL;
4771 *num_of_nodes = 0;
4772 }
4773 return rc;
4774}
4775
Linus Torvalds1da177e2005-04-16 15:20:36 -07004776int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004777CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004778 const char *search_name, struct dfs_info3_param **target_nodes,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004779 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004780 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004781{
4782/* TRANS2_GET_DFS_REFERRAL */
4783 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4784 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004785 int rc = 0;
4786 int bytes_returned;
4787 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004788 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004789 *num_of_nodes = 0;
4790 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004791
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004792 cFYI(1, "In GetDFSRefer the path %s", search_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004793 if (ses == NULL)
4794 return -ENODEV;
4795getDFSRetry:
4796 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4797 (void **) &pSMBr);
4798 if (rc)
4799 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004800
4801 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004802 but should never be null here anyway */
Pavel Shilovsky88257362012-05-23 14:01:59 +04004803 pSMB->hdr.Mid = get_next_mid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004804 pSMB->hdr.Tid = ses->ipc_tid;
4805 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004806 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004807 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004808 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004809 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004810
4811 if (ses->capabilities & CAP_UNICODE) {
4812 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4813 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004814 cifsConvertToUTF16((__le16 *) pSMB->RequestFileName,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004815 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004816 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004817 name_len++; /* trailing null */
4818 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004819 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004820 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004821 name_len++; /* trailing null */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004822 strncpy(pSMB->RequestFileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004823 }
4824
Steve French790fe572007-07-07 19:25:05 +00004825 if (ses->server) {
Steve French96daf2b2011-05-27 04:34:02 +00004826 if (ses->server->sec_mode &
Steve French1a4e15a2006-10-12 21:33:51 +00004827 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4828 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4829 }
4830
Steve French50c2f752007-07-13 00:33:32 +00004831 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004832
Linus Torvalds1da177e2005-04-16 15:20:36 -07004833 params = 2 /* level */ + name_len /*includes null */ ;
4834 pSMB->TotalDataCount = 0;
4835 pSMB->DataCount = 0;
4836 pSMB->DataOffset = 0;
4837 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004838 /* BB find exact max SMB PDU from sess structure BB */
4839 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004840 pSMB->MaxSetupCount = 0;
4841 pSMB->Reserved = 0;
4842 pSMB->Flags = 0;
4843 pSMB->Timeout = 0;
4844 pSMB->Reserved2 = 0;
4845 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004846 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004847 pSMB->SetupCount = 1;
4848 pSMB->Reserved3 = 0;
4849 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4850 byte_count = params + 3 /* pad */ ;
4851 pSMB->ParameterCount = cpu_to_le16(params);
4852 pSMB->TotalParameterCount = pSMB->ParameterCount;
4853 pSMB->MaxReferralLevel = cpu_to_le16(3);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004854 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004855 pSMB->ByteCount = cpu_to_le16(byte_count);
4856
4857 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4858 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4859 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004860 cFYI(1, "Send error in GetDFSRefer = %d", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004861 goto GetDFSRefExit;
4862 }
4863 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004864
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004865 /* BB Also check if enough total bytes returned? */
Jeff Layton820a8032011-05-04 08:05:26 -04004866 if (rc || get_bcc(&pSMBr->hdr) < 17) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004867 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004868 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004869 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004870
Joe Perchesb6b38f72010-04-21 03:50:45 +00004871 cFYI(1, "Decoding GetDFSRefer response BCC: %d Offset %d",
Jeff Layton820a8032011-05-04 08:05:26 -04004872 get_bcc(&pSMBr->hdr),
Joe Perchesb6b38f72010-04-21 03:50:45 +00004873 le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04004874
4875 /* parse returned result into more usable form */
Steve Frencha1fe78f2008-05-16 18:48:38 +00004876 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004877 target_nodes, nls_codepage, remap,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004878 search_name);
Igor Mammedovfec45852008-05-16 13:06:30 +04004879
Linus Torvalds1da177e2005-04-16 15:20:36 -07004880GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004881 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004882
4883 if (rc == -EAGAIN)
4884 goto getDFSRetry;
4885
4886 return rc;
4887}
4888
Steve French20962432005-09-21 22:05:57 -07004889/* Query File System Info such as free space to old servers such as Win 9x */
4890int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004891SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4892 struct kstatfs *FSData)
Steve French20962432005-09-21 22:05:57 -07004893{
4894/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4895 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4896 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4897 FILE_SYSTEM_ALLOC_INFO *response_data;
4898 int rc = 0;
4899 int bytes_returned = 0;
4900 __u16 params, byte_count;
4901
Joe Perchesb6b38f72010-04-21 03:50:45 +00004902 cFYI(1, "OldQFSInfo");
Steve French20962432005-09-21 22:05:57 -07004903oldQFSInfoRetry:
4904 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4905 (void **) &pSMBr);
4906 if (rc)
4907 return rc;
Steve French20962432005-09-21 22:05:57 -07004908
4909 params = 2; /* level */
4910 pSMB->TotalDataCount = 0;
4911 pSMB->MaxParameterCount = cpu_to_le16(2);
4912 pSMB->MaxDataCount = cpu_to_le16(1000);
4913 pSMB->MaxSetupCount = 0;
4914 pSMB->Reserved = 0;
4915 pSMB->Flags = 0;
4916 pSMB->Timeout = 0;
4917 pSMB->Reserved2 = 0;
4918 byte_count = params + 1 /* pad */ ;
4919 pSMB->TotalParameterCount = cpu_to_le16(params);
4920 pSMB->ParameterCount = pSMB->TotalParameterCount;
4921 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4922 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4923 pSMB->DataCount = 0;
4924 pSMB->DataOffset = 0;
4925 pSMB->SetupCount = 1;
4926 pSMB->Reserved3 = 0;
4927 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4928 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004929 inc_rfc1001_len(pSMB, byte_count);
Steve French20962432005-09-21 22:05:57 -07004930 pSMB->ByteCount = cpu_to_le16(byte_count);
4931
4932 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4933 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4934 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004935 cFYI(1, "Send error in QFSInfo = %d", rc);
Steve French20962432005-09-21 22:05:57 -07004936 } else { /* decode response */
4937 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4938
Jeff Layton820a8032011-05-04 08:05:26 -04004939 if (rc || get_bcc(&pSMBr->hdr) < 18)
Steve French20962432005-09-21 22:05:57 -07004940 rc = -EIO; /* bad smb */
4941 else {
4942 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004943 cFYI(1, "qfsinf resp BCC: %d Offset %d",
Jeff Layton820a8032011-05-04 08:05:26 -04004944 get_bcc(&pSMBr->hdr), data_offset);
Steve French20962432005-09-21 22:05:57 -07004945
Steve French50c2f752007-07-13 00:33:32 +00004946 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004947 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4948 FSData->f_bsize =
4949 le16_to_cpu(response_data->BytesPerSector) *
4950 le32_to_cpu(response_data->
4951 SectorsPerAllocationUnit);
4952 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004953 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004954 FSData->f_bfree = FSData->f_bavail =
4955 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004956 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
4957 (unsigned long long)FSData->f_blocks,
4958 (unsigned long long)FSData->f_bfree,
4959 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07004960 }
4961 }
4962 cifs_buf_release(pSMB);
4963
4964 if (rc == -EAGAIN)
4965 goto oldQFSInfoRetry;
4966
4967 return rc;
4968}
4969
Linus Torvalds1da177e2005-04-16 15:20:36 -07004970int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004971CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4972 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004973{
4974/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4975 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4976 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4977 FILE_SYSTEM_INFO *response_data;
4978 int rc = 0;
4979 int bytes_returned = 0;
4980 __u16 params, byte_count;
4981
Joe Perchesb6b38f72010-04-21 03:50:45 +00004982 cFYI(1, "In QFSInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004983QFSInfoRetry:
4984 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4985 (void **) &pSMBr);
4986 if (rc)
4987 return rc;
4988
4989 params = 2; /* level */
4990 pSMB->TotalDataCount = 0;
4991 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004992 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004993 pSMB->MaxSetupCount = 0;
4994 pSMB->Reserved = 0;
4995 pSMB->Flags = 0;
4996 pSMB->Timeout = 0;
4997 pSMB->Reserved2 = 0;
4998 byte_count = params + 1 /* pad */ ;
4999 pSMB->TotalParameterCount = cpu_to_le16(params);
5000 pSMB->ParameterCount = pSMB->TotalParameterCount;
5001 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005002 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005003 pSMB->DataCount = 0;
5004 pSMB->DataOffset = 0;
5005 pSMB->SetupCount = 1;
5006 pSMB->Reserved3 = 0;
5007 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5008 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005009 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005010 pSMB->ByteCount = cpu_to_le16(byte_count);
5011
5012 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5013 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5014 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005015 cFYI(1, "Send error in QFSInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005016 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00005017 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005018
Jeff Layton820a8032011-05-04 08:05:26 -04005019 if (rc || get_bcc(&pSMBr->hdr) < 24)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005020 rc = -EIO; /* bad smb */
5021 else {
5022 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005023
5024 response_data =
5025 (FILE_SYSTEM_INFO
5026 *) (((char *) &pSMBr->hdr.Protocol) +
5027 data_offset);
5028 FSData->f_bsize =
5029 le32_to_cpu(response_data->BytesPerSector) *
5030 le32_to_cpu(response_data->
5031 SectorsPerAllocationUnit);
5032 FSData->f_blocks =
5033 le64_to_cpu(response_data->TotalAllocationUnits);
5034 FSData->f_bfree = FSData->f_bavail =
5035 le64_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesb6b38f72010-04-21 03:50:45 +00005036 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
5037 (unsigned long long)FSData->f_blocks,
5038 (unsigned long long)FSData->f_bfree,
5039 FSData->f_bsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005040 }
5041 }
5042 cifs_buf_release(pSMB);
5043
5044 if (rc == -EAGAIN)
5045 goto QFSInfoRetry;
5046
5047 return rc;
5048}
5049
5050int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005051CIFSSMBQFSAttributeInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005052{
5053/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
5054 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5055 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5056 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
5057 int rc = 0;
5058 int bytes_returned = 0;
5059 __u16 params, byte_count;
5060
Joe Perchesb6b38f72010-04-21 03:50:45 +00005061 cFYI(1, "In QFSAttributeInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005062QFSAttributeRetry:
5063 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5064 (void **) &pSMBr);
5065 if (rc)
5066 return rc;
5067
5068 params = 2; /* level */
5069 pSMB->TotalDataCount = 0;
5070 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005071 /* BB find exact max SMB PDU from sess structure BB */
5072 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005073 pSMB->MaxSetupCount = 0;
5074 pSMB->Reserved = 0;
5075 pSMB->Flags = 0;
5076 pSMB->Timeout = 0;
5077 pSMB->Reserved2 = 0;
5078 byte_count = params + 1 /* pad */ ;
5079 pSMB->TotalParameterCount = cpu_to_le16(params);
5080 pSMB->ParameterCount = pSMB->TotalParameterCount;
5081 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005082 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005083 pSMB->DataCount = 0;
5084 pSMB->DataOffset = 0;
5085 pSMB->SetupCount = 1;
5086 pSMB->Reserved3 = 0;
5087 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5088 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005089 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005090 pSMB->ByteCount = cpu_to_le16(byte_count);
5091
5092 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5093 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5094 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005095 cERROR(1, "Send error in QFSAttributeInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005096 } else { /* decode response */
5097 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5098
Jeff Layton820a8032011-05-04 08:05:26 -04005099 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Steve French50c2f752007-07-13 00:33:32 +00005100 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005101 rc = -EIO; /* bad smb */
5102 } else {
5103 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5104 response_data =
5105 (FILE_SYSTEM_ATTRIBUTE_INFO
5106 *) (((char *) &pSMBr->hdr.Protocol) +
5107 data_offset);
5108 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005109 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005110 }
5111 }
5112 cifs_buf_release(pSMB);
5113
5114 if (rc == -EAGAIN)
5115 goto QFSAttributeRetry;
5116
5117 return rc;
5118}
5119
5120int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005121CIFSSMBQFSDeviceInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005122{
5123/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
5124 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5125 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5126 FILE_SYSTEM_DEVICE_INFO *response_data;
5127 int rc = 0;
5128 int bytes_returned = 0;
5129 __u16 params, byte_count;
5130
Joe Perchesb6b38f72010-04-21 03:50:45 +00005131 cFYI(1, "In QFSDeviceInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005132QFSDeviceRetry:
5133 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5134 (void **) &pSMBr);
5135 if (rc)
5136 return rc;
5137
5138 params = 2; /* level */
5139 pSMB->TotalDataCount = 0;
5140 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005141 /* BB find exact max SMB PDU from sess structure BB */
5142 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005143 pSMB->MaxSetupCount = 0;
5144 pSMB->Reserved = 0;
5145 pSMB->Flags = 0;
5146 pSMB->Timeout = 0;
5147 pSMB->Reserved2 = 0;
5148 byte_count = params + 1 /* pad */ ;
5149 pSMB->TotalParameterCount = cpu_to_le16(params);
5150 pSMB->ParameterCount = pSMB->TotalParameterCount;
5151 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005152 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005153
5154 pSMB->DataCount = 0;
5155 pSMB->DataOffset = 0;
5156 pSMB->SetupCount = 1;
5157 pSMB->Reserved3 = 0;
5158 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5159 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005160 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005161 pSMB->ByteCount = cpu_to_le16(byte_count);
5162
5163 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5164 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5165 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005166 cFYI(1, "Send error in QFSDeviceInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005167 } else { /* decode response */
5168 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5169
Jeff Layton820a8032011-05-04 08:05:26 -04005170 if (rc || get_bcc(&pSMBr->hdr) <
5171 sizeof(FILE_SYSTEM_DEVICE_INFO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005172 rc = -EIO; /* bad smb */
5173 else {
5174 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5175 response_data =
Steve French737b7582005-04-28 22:41:06 -07005176 (FILE_SYSTEM_DEVICE_INFO *)
5177 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07005178 data_offset);
5179 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005180 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005181 }
5182 }
5183 cifs_buf_release(pSMB);
5184
5185 if (rc == -EAGAIN)
5186 goto QFSDeviceRetry;
5187
5188 return rc;
5189}
5190
5191int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005192CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005193{
5194/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
5195 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5196 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5197 FILE_SYSTEM_UNIX_INFO *response_data;
5198 int rc = 0;
5199 int bytes_returned = 0;
5200 __u16 params, byte_count;
5201
Joe Perchesb6b38f72010-04-21 03:50:45 +00005202 cFYI(1, "In QFSUnixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005203QFSUnixRetry:
Jeff Laytonf5695992010-09-29 15:27:08 -04005204 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5205 (void **) &pSMB, (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005206 if (rc)
5207 return rc;
5208
5209 params = 2; /* level */
5210 pSMB->TotalDataCount = 0;
5211 pSMB->DataCount = 0;
5212 pSMB->DataOffset = 0;
5213 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005214 /* BB find exact max SMB PDU from sess structure BB */
5215 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005216 pSMB->MaxSetupCount = 0;
5217 pSMB->Reserved = 0;
5218 pSMB->Flags = 0;
5219 pSMB->Timeout = 0;
5220 pSMB->Reserved2 = 0;
5221 byte_count = params + 1 /* pad */ ;
5222 pSMB->ParameterCount = cpu_to_le16(params);
5223 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005224 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5225 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005226 pSMB->SetupCount = 1;
5227 pSMB->Reserved3 = 0;
5228 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5229 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005230 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005231 pSMB->ByteCount = cpu_to_le16(byte_count);
5232
5233 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5234 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5235 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005236 cERROR(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005237 } else { /* decode response */
5238 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5239
Jeff Layton820a8032011-05-04 08:05:26 -04005240 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005241 rc = -EIO; /* bad smb */
5242 } else {
5243 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5244 response_data =
5245 (FILE_SYSTEM_UNIX_INFO
5246 *) (((char *) &pSMBr->hdr.Protocol) +
5247 data_offset);
5248 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005249 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005250 }
5251 }
5252 cifs_buf_release(pSMB);
5253
5254 if (rc == -EAGAIN)
5255 goto QFSUnixRetry;
5256
5257
5258 return rc;
5259}
5260
Jeremy Allisonac670552005-06-22 17:26:35 -07005261int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005262CIFSSMBSetFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07005263{
5264/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
5265 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
5266 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
5267 int rc = 0;
5268 int bytes_returned = 0;
5269 __u16 params, param_offset, offset, byte_count;
5270
Joe Perchesb6b38f72010-04-21 03:50:45 +00005271 cFYI(1, "In SETFSUnixInfo");
Jeremy Allisonac670552005-06-22 17:26:35 -07005272SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00005273 /* BB switch to small buf init to save memory */
Jeff Laytonf5695992010-09-29 15:27:08 -04005274 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5275 (void **) &pSMB, (void **) &pSMBr);
Jeremy Allisonac670552005-06-22 17:26:35 -07005276 if (rc)
5277 return rc;
5278
5279 params = 4; /* 2 bytes zero followed by info level. */
5280 pSMB->MaxSetupCount = 0;
5281 pSMB->Reserved = 0;
5282 pSMB->Flags = 0;
5283 pSMB->Timeout = 0;
5284 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00005285 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
5286 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07005287 offset = param_offset + params;
5288
5289 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00005290 /* BB find exact max SMB PDU from sess structure BB */
5291 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07005292 pSMB->SetupCount = 1;
5293 pSMB->Reserved3 = 0;
5294 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
5295 byte_count = 1 /* pad */ + params + 12;
5296
5297 pSMB->DataCount = cpu_to_le16(12);
5298 pSMB->ParameterCount = cpu_to_le16(params);
5299 pSMB->TotalDataCount = pSMB->DataCount;
5300 pSMB->TotalParameterCount = pSMB->ParameterCount;
5301 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5302 pSMB->DataOffset = cpu_to_le16(offset);
5303
5304 /* Params. */
5305 pSMB->FileNum = 0;
5306 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
5307
5308 /* Data. */
5309 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
5310 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
5311 pSMB->ClientUnixCap = cpu_to_le64(cap);
5312
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005313 inc_rfc1001_len(pSMB, byte_count);
Jeremy Allisonac670552005-06-22 17:26:35 -07005314 pSMB->ByteCount = cpu_to_le16(byte_count);
5315
5316 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5317 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5318 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005319 cERROR(1, "Send error in SETFSUnixInfo = %d", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07005320 } else { /* decode response */
5321 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00005322 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07005323 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07005324 }
5325 cifs_buf_release(pSMB);
5326
5327 if (rc == -EAGAIN)
5328 goto SETFSUnixRetry;
5329
5330 return rc;
5331}
5332
5333
Linus Torvalds1da177e2005-04-16 15:20:36 -07005334
5335int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005336CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon,
Steve French737b7582005-04-28 22:41:06 -07005337 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005338{
5339/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
5340 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5341 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5342 FILE_SYSTEM_POSIX_INFO *response_data;
5343 int rc = 0;
5344 int bytes_returned = 0;
5345 __u16 params, byte_count;
5346
Joe Perchesb6b38f72010-04-21 03:50:45 +00005347 cFYI(1, "In QFSPosixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005348QFSPosixRetry:
5349 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5350 (void **) &pSMBr);
5351 if (rc)
5352 return rc;
5353
5354 params = 2; /* level */
5355 pSMB->TotalDataCount = 0;
5356 pSMB->DataCount = 0;
5357 pSMB->DataOffset = 0;
5358 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005359 /* BB find exact max SMB PDU from sess structure BB */
5360 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005361 pSMB->MaxSetupCount = 0;
5362 pSMB->Reserved = 0;
5363 pSMB->Flags = 0;
5364 pSMB->Timeout = 0;
5365 pSMB->Reserved2 = 0;
5366 byte_count = params + 1 /* pad */ ;
5367 pSMB->ParameterCount = cpu_to_le16(params);
5368 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005369 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5370 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005371 pSMB->SetupCount = 1;
5372 pSMB->Reserved3 = 0;
5373 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5374 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005375 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005376 pSMB->ByteCount = cpu_to_le16(byte_count);
5377
5378 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5379 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5380 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005381 cFYI(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005382 } else { /* decode response */
5383 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5384
Jeff Layton820a8032011-05-04 08:05:26 -04005385 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005386 rc = -EIO; /* bad smb */
5387 } else {
5388 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5389 response_data =
5390 (FILE_SYSTEM_POSIX_INFO
5391 *) (((char *) &pSMBr->hdr.Protocol) +
5392 data_offset);
5393 FSData->f_bsize =
5394 le32_to_cpu(response_data->BlockSize);
5395 FSData->f_blocks =
5396 le64_to_cpu(response_data->TotalBlocks);
5397 FSData->f_bfree =
5398 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00005399 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005400 FSData->f_bavail = FSData->f_bfree;
5401 } else {
5402 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00005403 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005404 }
Steve French790fe572007-07-07 19:25:05 +00005405 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005406 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00005407 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00005408 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005409 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00005410 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005411 }
5412 }
5413 cifs_buf_release(pSMB);
5414
5415 if (rc == -EAGAIN)
5416 goto QFSPosixRetry;
5417
5418 return rc;
5419}
5420
5421
Steve French50c2f752007-07-13 00:33:32 +00005422/* We can not use write of zero bytes trick to
5423 set file size due to need for large file support. Also note that
5424 this SetPathInfo is preferred to SetFileInfo based method in next
Linus Torvalds1da177e2005-04-16 15:20:36 -07005425 routine which is only needed to work around a sharing violation bug
5426 in Samba which this routine can run into */
5427
5428int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005429CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
5430 const char *fileName, __u64 size, bool SetAllocation,
Steve French737b7582005-04-28 22:41:06 -07005431 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005432{
5433 struct smb_com_transaction2_spi_req *pSMB = NULL;
5434 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5435 struct file_end_of_file_info *parm_data;
5436 int name_len;
5437 int rc = 0;
5438 int bytes_returned = 0;
5439 __u16 params, byte_count, data_count, param_offset, offset;
5440
Joe Perchesb6b38f72010-04-21 03:50:45 +00005441 cFYI(1, "In SetEOF");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005442SetEOFRetry:
5443 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5444 (void **) &pSMBr);
5445 if (rc)
5446 return rc;
5447
5448 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5449 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005450 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5451 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005452 name_len++; /* trailing null */
5453 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005454 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005455 name_len = strnlen(fileName, PATH_MAX);
5456 name_len++; /* trailing null */
5457 strncpy(pSMB->FileName, fileName, name_len);
5458 }
5459 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005460 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005461 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07005462 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005463 pSMB->MaxSetupCount = 0;
5464 pSMB->Reserved = 0;
5465 pSMB->Flags = 0;
5466 pSMB->Timeout = 0;
5467 pSMB->Reserved2 = 0;
5468 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005469 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005470 offset = param_offset + params;
Steve French790fe572007-07-07 19:25:05 +00005471 if (SetAllocation) {
Steve French50c2f752007-07-13 00:33:32 +00005472 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5473 pSMB->InformationLevel =
5474 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5475 else
5476 pSMB->InformationLevel =
5477 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5478 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005479 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5480 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005481 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005482 else
5483 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005484 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005485 }
5486
5487 parm_data =
5488 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
5489 offset);
5490 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5491 pSMB->DataOffset = cpu_to_le16(offset);
5492 pSMB->SetupCount = 1;
5493 pSMB->Reserved3 = 0;
5494 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5495 byte_count = 3 /* pad */ + params + data_count;
5496 pSMB->DataCount = cpu_to_le16(data_count);
5497 pSMB->TotalDataCount = pSMB->DataCount;
5498 pSMB->ParameterCount = cpu_to_le16(params);
5499 pSMB->TotalParameterCount = pSMB->ParameterCount;
5500 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005501 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005502 parm_data->FileSize = cpu_to_le64(size);
5503 pSMB->ByteCount = cpu_to_le16(byte_count);
5504 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5505 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005506 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005507 cFYI(1, "SetPathInfo (file size) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005508
5509 cifs_buf_release(pSMB);
5510
5511 if (rc == -EAGAIN)
5512 goto SetEOFRetry;
5513
5514 return rc;
5515}
5516
5517int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005518CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon, __u64 size,
Steve French4b18f2a2008-04-29 00:06:05 +00005519 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005520{
5521 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005522 struct file_end_of_file_info *parm_data;
5523 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005524 __u16 params, param_offset, offset, byte_count, count;
5525
Joe Perchesb6b38f72010-04-21 03:50:45 +00005526 cFYI(1, "SetFileSize (via SetFileInfo) %lld",
5527 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07005528 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5529
Linus Torvalds1da177e2005-04-16 15:20:36 -07005530 if (rc)
5531 return rc;
5532
5533 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5534 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005535
Linus Torvalds1da177e2005-04-16 15:20:36 -07005536 params = 6;
5537 pSMB->MaxSetupCount = 0;
5538 pSMB->Reserved = 0;
5539 pSMB->Flags = 0;
5540 pSMB->Timeout = 0;
5541 pSMB->Reserved2 = 0;
5542 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5543 offset = param_offset + params;
5544
Linus Torvalds1da177e2005-04-16 15:20:36 -07005545 count = sizeof(struct file_end_of_file_info);
5546 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005547 /* BB find exact max SMB PDU from sess structure BB */
5548 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005549 pSMB->SetupCount = 1;
5550 pSMB->Reserved3 = 0;
5551 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5552 byte_count = 3 /* pad */ + params + count;
5553 pSMB->DataCount = cpu_to_le16(count);
5554 pSMB->ParameterCount = cpu_to_le16(params);
5555 pSMB->TotalDataCount = pSMB->DataCount;
5556 pSMB->TotalParameterCount = pSMB->ParameterCount;
5557 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5558 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00005559 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
5560 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005561 pSMB->DataOffset = cpu_to_le16(offset);
5562 parm_data->FileSize = cpu_to_le64(size);
5563 pSMB->Fid = fid;
Steve French790fe572007-07-07 19:25:05 +00005564 if (SetAllocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005565 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5566 pSMB->InformationLevel =
5567 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5568 else
5569 pSMB->InformationLevel =
5570 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00005571 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005572 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5573 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005574 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005575 else
5576 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005577 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005578 }
5579 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005580 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005581 pSMB->ByteCount = cpu_to_le16(byte_count);
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005582 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005583 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005584 cFYI(1, "Send error in SetFileInfo (SetFileSize) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005585 }
5586
Steve French50c2f752007-07-13 00:33:32 +00005587 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005588 since file handle passed in no longer valid */
5589
5590 return rc;
5591}
5592
Steve French50c2f752007-07-13 00:33:32 +00005593/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07005594 an open handle, rather than by pathname - this is awkward due to
5595 potential access conflicts on the open, but it is unavoidable for these
5596 old servers since the only other choice is to go from 100 nanosecond DCE
5597 time and resort to the original setpathinfo level which takes the ancient
5598 DOS time format with 2 second granularity */
5599int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005600CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005601 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005602{
5603 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005604 char *data_offset;
5605 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005606 __u16 params, param_offset, offset, byte_count, count;
5607
Joe Perchesb6b38f72010-04-21 03:50:45 +00005608 cFYI(1, "Set Times (via SetFileInfo)");
Steve Frenchcd634992005-04-28 22:41:10 -07005609 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5610
Linus Torvalds1da177e2005-04-16 15:20:36 -07005611 if (rc)
5612 return rc;
5613
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005614 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5615 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005616
Linus Torvalds1da177e2005-04-16 15:20:36 -07005617 params = 6;
5618 pSMB->MaxSetupCount = 0;
5619 pSMB->Reserved = 0;
5620 pSMB->Flags = 0;
5621 pSMB->Timeout = 0;
5622 pSMB->Reserved2 = 0;
5623 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5624 offset = param_offset + params;
5625
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005626 data_offset = (char *)pSMB +
5627 offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005628
Steve French26f57362007-08-30 22:09:15 +00005629 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005630 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005631 /* BB find max SMB PDU from sess */
5632 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005633 pSMB->SetupCount = 1;
5634 pSMB->Reserved3 = 0;
5635 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5636 byte_count = 3 /* pad */ + params + count;
5637 pSMB->DataCount = cpu_to_le16(count);
5638 pSMB->ParameterCount = cpu_to_le16(params);
5639 pSMB->TotalDataCount = pSMB->DataCount;
5640 pSMB->TotalParameterCount = pSMB->ParameterCount;
5641 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5642 pSMB->DataOffset = cpu_to_le16(offset);
5643 pSMB->Fid = fid;
5644 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5645 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5646 else
5647 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5648 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005649 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005650 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005651 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005652 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005653 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005654 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005655
Steve French50c2f752007-07-13 00:33:32 +00005656 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005657 since file handle passed in no longer valid */
5658
5659 return rc;
5660}
5661
Jeff Layton6d22f092008-09-23 11:48:35 -04005662int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005663CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6d22f092008-09-23 11:48:35 -04005664 bool delete_file, __u16 fid, __u32 pid_of_opener)
5665{
5666 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5667 char *data_offset;
5668 int rc = 0;
5669 __u16 params, param_offset, offset, byte_count, count;
5670
Joe Perchesb6b38f72010-04-21 03:50:45 +00005671 cFYI(1, "Set File Disposition (via SetFileInfo)");
Jeff Layton6d22f092008-09-23 11:48:35 -04005672 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5673
5674 if (rc)
5675 return rc;
5676
5677 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5678 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5679
5680 params = 6;
5681 pSMB->MaxSetupCount = 0;
5682 pSMB->Reserved = 0;
5683 pSMB->Flags = 0;
5684 pSMB->Timeout = 0;
5685 pSMB->Reserved2 = 0;
5686 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5687 offset = param_offset + params;
5688
5689 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5690
5691 count = 1;
5692 pSMB->MaxParameterCount = cpu_to_le16(2);
5693 /* BB find max SMB PDU from sess */
5694 pSMB->MaxDataCount = cpu_to_le16(1000);
5695 pSMB->SetupCount = 1;
5696 pSMB->Reserved3 = 0;
5697 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5698 byte_count = 3 /* pad */ + params + count;
5699 pSMB->DataCount = cpu_to_le16(count);
5700 pSMB->ParameterCount = cpu_to_le16(params);
5701 pSMB->TotalDataCount = pSMB->DataCount;
5702 pSMB->TotalParameterCount = pSMB->ParameterCount;
5703 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5704 pSMB->DataOffset = cpu_to_le16(offset);
5705 pSMB->Fid = fid;
5706 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5707 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005708 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton6d22f092008-09-23 11:48:35 -04005709 pSMB->ByteCount = cpu_to_le16(byte_count);
5710 *data_offset = delete_file ? 1 : 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005711 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Jeff Layton6d22f092008-09-23 11:48:35 -04005712 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005713 cFYI(1, "Send error in SetFileDisposition = %d", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005714
5715 return rc;
5716}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005717
5718int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005719CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6fc000e2008-08-02 07:26:12 -04005720 const char *fileName, const FILE_BASIC_INFO *data,
5721 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005722{
5723 TRANSACTION2_SPI_REQ *pSMB = NULL;
5724 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5725 int name_len;
5726 int rc = 0;
5727 int bytes_returned = 0;
5728 char *data_offset;
5729 __u16 params, param_offset, offset, byte_count, count;
5730
Joe Perchesb6b38f72010-04-21 03:50:45 +00005731 cFYI(1, "In SetTimes");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005732
5733SetTimesRetry:
5734 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5735 (void **) &pSMBr);
5736 if (rc)
5737 return rc;
5738
5739 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5740 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005741 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5742 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005743 name_len++; /* trailing null */
5744 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005745 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005746 name_len = strnlen(fileName, PATH_MAX);
5747 name_len++; /* trailing null */
5748 strncpy(pSMB->FileName, fileName, name_len);
5749 }
5750
5751 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005752 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005753 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005754 /* BB find max SMB PDU from sess structure BB */
5755 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005756 pSMB->MaxSetupCount = 0;
5757 pSMB->Reserved = 0;
5758 pSMB->Flags = 0;
5759 pSMB->Timeout = 0;
5760 pSMB->Reserved2 = 0;
5761 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005762 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005763 offset = param_offset + params;
5764 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5765 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5766 pSMB->DataOffset = cpu_to_le16(offset);
5767 pSMB->SetupCount = 1;
5768 pSMB->Reserved3 = 0;
5769 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5770 byte_count = 3 /* pad */ + params + count;
5771
5772 pSMB->DataCount = cpu_to_le16(count);
5773 pSMB->ParameterCount = cpu_to_le16(params);
5774 pSMB->TotalDataCount = pSMB->DataCount;
5775 pSMB->TotalParameterCount = pSMB->ParameterCount;
5776 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5777 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5778 else
5779 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5780 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005781 inc_rfc1001_len(pSMB, byte_count);
Steve French26f57362007-08-30 22:09:15 +00005782 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005783 pSMB->ByteCount = cpu_to_le16(byte_count);
5784 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5785 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005786 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005787 cFYI(1, "SetPathInfo (times) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005788
5789 cifs_buf_release(pSMB);
5790
5791 if (rc == -EAGAIN)
5792 goto SetTimesRetry;
5793
5794 return rc;
5795}
5796
5797/* Can not be used to set time stamps yet (due to old DOS time format) */
5798/* Can be used to set attributes */
5799#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5800 handling it anyway and NT4 was what we thought it would be needed for
5801 Do not delete it until we prove whether needed for Win9x though */
5802int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005803CIFSSMBSetAttrLegacy(unsigned int xid, struct cifs_tcon *tcon, char *fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005804 __u16 dos_attrs, const struct nls_table *nls_codepage)
5805{
5806 SETATTR_REQ *pSMB = NULL;
5807 SETATTR_RSP *pSMBr = NULL;
5808 int rc = 0;
5809 int bytes_returned;
5810 int name_len;
5811
Joe Perchesb6b38f72010-04-21 03:50:45 +00005812 cFYI(1, "In SetAttrLegacy");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005813
5814SetAttrLgcyRetry:
5815 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5816 (void **) &pSMBr);
5817 if (rc)
5818 return rc;
5819
5820 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5821 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005822 ConvertToUTF16((__le16 *) pSMB->fileName, fileName,
5823 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005824 name_len++; /* trailing null */
5825 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005826 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005827 name_len = strnlen(fileName, PATH_MAX);
5828 name_len++; /* trailing null */
5829 strncpy(pSMB->fileName, fileName, name_len);
5830 }
5831 pSMB->attr = cpu_to_le16(dos_attrs);
5832 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005833 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005834 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5835 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5836 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005837 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005838 cFYI(1, "Error in LegacySetAttr = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005839
5840 cifs_buf_release(pSMB);
5841
5842 if (rc == -EAGAIN)
5843 goto SetAttrLgcyRetry;
5844
5845 return rc;
5846}
5847#endif /* temporarily unneeded SetAttr legacy function */
5848
Jeff Layton654cf142009-07-09 20:02:49 -04005849static void
5850cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5851 const struct cifs_unix_set_info_args *args)
5852{
5853 u64 mode = args->mode;
5854
5855 /*
5856 * Samba server ignores set of file size to zero due to bugs in some
5857 * older clients, but we should be precise - we use SetFileSize to
5858 * set file size and do not want to truncate file size to zero
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005859 * accidentally as happened on one Samba server beta by putting
Jeff Layton654cf142009-07-09 20:02:49 -04005860 * zero instead of -1 here
5861 */
5862 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5863 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5864 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5865 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5866 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5867 data_offset->Uid = cpu_to_le64(args->uid);
5868 data_offset->Gid = cpu_to_le64(args->gid);
5869 /* better to leave device as zero when it is */
5870 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5871 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5872 data_offset->Permissions = cpu_to_le64(mode);
5873
5874 if (S_ISREG(mode))
5875 data_offset->Type = cpu_to_le32(UNIX_FILE);
5876 else if (S_ISDIR(mode))
5877 data_offset->Type = cpu_to_le32(UNIX_DIR);
5878 else if (S_ISLNK(mode))
5879 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5880 else if (S_ISCHR(mode))
5881 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5882 else if (S_ISBLK(mode))
5883 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5884 else if (S_ISFIFO(mode))
5885 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5886 else if (S_ISSOCK(mode))
5887 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5888}
5889
Linus Torvalds1da177e2005-04-16 15:20:36 -07005890int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005891CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005892 const struct cifs_unix_set_info_args *args,
5893 u16 fid, u32 pid_of_opener)
5894{
5895 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005896 char *data_offset;
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005897 int rc = 0;
5898 u16 params, param_offset, offset, byte_count, count;
5899
Joe Perchesb6b38f72010-04-21 03:50:45 +00005900 cFYI(1, "Set Unix Info (via SetFileInfo)");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005901 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5902
5903 if (rc)
5904 return rc;
5905
5906 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5907 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5908
5909 params = 6;
5910 pSMB->MaxSetupCount = 0;
5911 pSMB->Reserved = 0;
5912 pSMB->Flags = 0;
5913 pSMB->Timeout = 0;
5914 pSMB->Reserved2 = 0;
5915 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5916 offset = param_offset + params;
5917
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005918 data_offset = (char *)pSMB +
5919 offsetof(struct smb_hdr, Protocol) + offset;
5920
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005921 count = sizeof(FILE_UNIX_BASIC_INFO);
5922
5923 pSMB->MaxParameterCount = cpu_to_le16(2);
5924 /* BB find max SMB PDU from sess */
5925 pSMB->MaxDataCount = cpu_to_le16(1000);
5926 pSMB->SetupCount = 1;
5927 pSMB->Reserved3 = 0;
5928 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5929 byte_count = 3 /* pad */ + params + count;
5930 pSMB->DataCount = cpu_to_le16(count);
5931 pSMB->ParameterCount = cpu_to_le16(params);
5932 pSMB->TotalDataCount = pSMB->DataCount;
5933 pSMB->TotalParameterCount = pSMB->ParameterCount;
5934 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5935 pSMB->DataOffset = cpu_to_le16(offset);
5936 pSMB->Fid = fid;
5937 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5938 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005939 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005940 pSMB->ByteCount = cpu_to_le16(byte_count);
5941
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005942 cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005943
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005944 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005945 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005946 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005947
5948 /* Note: On -EAGAIN error only caller can retry on handle based calls
5949 since file handle passed in no longer valid */
5950
5951 return rc;
5952}
5953
5954int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005955CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005956 const char *file_name,
Jeff Layton01ea95e2009-07-09 20:02:49 -04005957 const struct cifs_unix_set_info_args *args,
5958 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005959{
5960 TRANSACTION2_SPI_REQ *pSMB = NULL;
5961 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5962 int name_len;
5963 int rc = 0;
5964 int bytes_returned = 0;
5965 FILE_UNIX_BASIC_INFO *data_offset;
5966 __u16 params, param_offset, offset, count, byte_count;
5967
Joe Perchesb6b38f72010-04-21 03:50:45 +00005968 cFYI(1, "In SetUID/GID/Mode");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005969setPermsRetry:
5970 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5971 (void **) &pSMBr);
5972 if (rc)
5973 return rc;
5974
5975 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5976 name_len =
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005977 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06005978 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005979 name_len++; /* trailing null */
5980 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005981 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005982 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005983 name_len++; /* trailing null */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04005984 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005985 }
5986
5987 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005988 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005989 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005990 /* BB find max SMB PDU from sess structure BB */
5991 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005992 pSMB->MaxSetupCount = 0;
5993 pSMB->Reserved = 0;
5994 pSMB->Flags = 0;
5995 pSMB->Timeout = 0;
5996 pSMB->Reserved2 = 0;
5997 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005998 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005999 offset = param_offset + params;
6000 data_offset =
6001 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
6002 offset);
6003 memset(data_offset, 0, count);
6004 pSMB->DataOffset = cpu_to_le16(offset);
6005 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6006 pSMB->SetupCount = 1;
6007 pSMB->Reserved3 = 0;
6008 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6009 byte_count = 3 /* pad */ + params + count;
6010 pSMB->ParameterCount = cpu_to_le16(params);
6011 pSMB->DataCount = cpu_to_le16(count);
6012 pSMB->TotalParameterCount = pSMB->ParameterCount;
6013 pSMB->TotalDataCount = pSMB->DataCount;
6014 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6015 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006016 inc_rfc1001_len(pSMB, byte_count);
Steve French50c2f752007-07-13 00:33:32 +00006017
Jeff Layton654cf142009-07-09 20:02:49 -04006018 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006019
6020 pSMB->ByteCount = cpu_to_le16(byte_count);
6021 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6022 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006023 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00006024 cFYI(1, "SetPathInfo (perms) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006025
Steve French0d817bc2008-05-22 02:02:03 +00006026 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006027 if (rc == -EAGAIN)
6028 goto setPermsRetry;
6029 return rc;
6030}
6031
Linus Torvalds1da177e2005-04-16 15:20:36 -07006032#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05006033/*
6034 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
6035 * function used by listxattr and getxattr type calls. When ea_name is set,
6036 * it looks for that attribute name and stuffs that value into the EAData
6037 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
6038 * buffer. In both cases, the return value is either the length of the
6039 * resulting data or a negative error code. If EAData is a NULL pointer then
6040 * the data isn't copied to it, but the length is returned.
6041 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006042ssize_t
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006043CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05006044 const unsigned char *searchName, const unsigned char *ea_name,
6045 char *EAData, size_t buf_size,
6046 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006047{
6048 /* BB assumes one setup word */
6049 TRANSACTION2_QPI_REQ *pSMB = NULL;
6050 TRANSACTION2_QPI_RSP *pSMBr = NULL;
6051 int rc = 0;
6052 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05006053 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006054 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00006055 struct fea *temp_fea;
6056 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006057 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006058 __u16 params, byte_count, data_offset;
Jeff Layton5980fc92011-07-28 12:48:26 -04006059 unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006060
Joe Perchesb6b38f72010-04-21 03:50:45 +00006061 cFYI(1, "In Query All EAs path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006062QAllEAsRetry:
6063 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6064 (void **) &pSMBr);
6065 if (rc)
6066 return rc;
6067
6068 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05006069 list_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006070 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
6071 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05006072 list_len++; /* trailing null */
6073 list_len *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006074 } else { /* BB improve the check for buffer overruns BB */
Jeff Layton6e462b92010-02-10 16:18:26 -05006075 list_len = strnlen(searchName, PATH_MAX);
6076 list_len++; /* trailing null */
6077 strncpy(pSMB->FileName, searchName, list_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006078 }
6079
Jeff Layton6e462b92010-02-10 16:18:26 -05006080 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006081 pSMB->TotalDataCount = 0;
6082 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006083 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05006084 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006085 pSMB->MaxSetupCount = 0;
6086 pSMB->Reserved = 0;
6087 pSMB->Flags = 0;
6088 pSMB->Timeout = 0;
6089 pSMB->Reserved2 = 0;
6090 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00006091 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006092 pSMB->DataCount = 0;
6093 pSMB->DataOffset = 0;
6094 pSMB->SetupCount = 1;
6095 pSMB->Reserved3 = 0;
6096 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
6097 byte_count = params + 1 /* pad */ ;
6098 pSMB->TotalParameterCount = cpu_to_le16(params);
6099 pSMB->ParameterCount = pSMB->TotalParameterCount;
6100 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
6101 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006102 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006103 pSMB->ByteCount = cpu_to_le16(byte_count);
6104
6105 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6106 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6107 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006108 cFYI(1, "Send error in QueryAllEAs = %d", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05006109 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006110 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006111
6112
6113 /* BB also check enough total bytes returned */
6114 /* BB we need to improve the validity checking
6115 of these trans2 responses */
6116
6117 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Jeff Layton820a8032011-05-04 08:05:26 -04006118 if (rc || get_bcc(&pSMBr->hdr) < 4) {
Jeff Laytonf0d38682010-02-10 16:18:26 -05006119 rc = -EIO; /* bad smb */
6120 goto QAllEAsOut;
6121 }
6122
6123 /* check that length of list is not more than bcc */
6124 /* check that each entry does not go beyond length
6125 of list */
6126 /* check that each element of each entry does not
6127 go beyond end of list */
6128 /* validate_trans2_offsets() */
6129 /* BB check if start of smb + data_offset > &bcc+ bcc */
6130
6131 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
6132 ea_response_data = (struct fealist *)
6133 (((char *) &pSMBr->hdr.Protocol) + data_offset);
6134
Jeff Layton6e462b92010-02-10 16:18:26 -05006135 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesb6b38f72010-04-21 03:50:45 +00006136 cFYI(1, "ea length %d", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05006137 if (list_len <= 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006138 cFYI(1, "empty EA list returned from server");
Jeff Laytonf0d38682010-02-10 16:18:26 -05006139 goto QAllEAsOut;
6140 }
6141
Jeff Layton0cd126b2010-02-10 16:18:26 -05006142 /* make sure list_len doesn't go past end of SMB */
Jeff Layton690c5222011-01-20 13:36:51 -05006143 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
Jeff Layton0cd126b2010-02-10 16:18:26 -05006144 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006145 cFYI(1, "EA list appears to go beyond SMB");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006146 rc = -EIO;
6147 goto QAllEAsOut;
6148 }
6149
Jeff Laytonf0d38682010-02-10 16:18:26 -05006150 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05006151 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006152 temp_fea = ea_response_data->list;
6153 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05006154 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00006155 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006156 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006157
Jeff Layton6e462b92010-02-10 16:18:26 -05006158 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006159 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006160 /* make sure we can read name_len and value_len */
6161 if (list_len < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006162 cFYI(1, "EA entry goes beyond length of list");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006163 rc = -EIO;
6164 goto QAllEAsOut;
6165 }
6166
6167 name_len = temp_fea->name_len;
6168 value_len = le16_to_cpu(temp_fea->value_len);
6169 list_len -= name_len + 1 + value_len;
6170 if (list_len < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00006171 cFYI(1, "EA entry goes beyond length of list");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006172 rc = -EIO;
6173 goto QAllEAsOut;
6174 }
6175
Jeff Layton31c05192010-02-10 16:18:26 -05006176 if (ea_name) {
Jeff Layton91d065c2011-07-26 18:23:47 -04006177 if (ea_name_len == name_len &&
Jeff Laytonac423442011-10-11 06:41:32 -04006178 memcmp(ea_name, temp_ptr, name_len) == 0) {
Jeff Layton31c05192010-02-10 16:18:26 -05006179 temp_ptr += name_len + 1;
6180 rc = value_len;
6181 if (buf_size == 0)
6182 goto QAllEAsOut;
6183 if ((size_t)value_len > buf_size) {
6184 rc = -ERANGE;
6185 goto QAllEAsOut;
6186 }
6187 memcpy(EAData, temp_ptr, value_len);
6188 goto QAllEAsOut;
6189 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006190 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05006191 /* account for prefix user. and trailing null */
6192 rc += (5 + 1 + name_len);
6193 if (rc < (int) buf_size) {
6194 memcpy(EAData, "user.", 5);
6195 EAData += 5;
6196 memcpy(EAData, temp_ptr, name_len);
6197 EAData += name_len;
6198 /* null terminate name */
6199 *EAData = 0;
6200 ++EAData;
6201 } else if (buf_size == 0) {
6202 /* skip copy - calc size only */
6203 } else {
6204 /* stop before overrun buffer */
6205 rc = -ERANGE;
6206 break;
6207 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006208 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05006209 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006210 temp_fea = (struct fea *)temp_ptr;
6211 }
6212
Jeff Layton31c05192010-02-10 16:18:26 -05006213 /* didn't find the named attribute */
6214 if (ea_name)
6215 rc = -ENODATA;
6216
Jeff Laytonf0d38682010-02-10 16:18:26 -05006217QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00006218 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006219 if (rc == -EAGAIN)
6220 goto QAllEAsRetry;
6221
6222 return (ssize_t)rc;
6223}
6224
Linus Torvalds1da177e2005-04-16 15:20:36 -07006225int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006226CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
6227 const char *fileName, const char *ea_name, const void *ea_value,
Steve French50c2f752007-07-13 00:33:32 +00006228 const __u16 ea_value_len, const struct nls_table *nls_codepage,
6229 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006230{
6231 struct smb_com_transaction2_spi_req *pSMB = NULL;
6232 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
6233 struct fealist *parm_data;
6234 int name_len;
6235 int rc = 0;
6236 int bytes_returned = 0;
6237 __u16 params, param_offset, byte_count, offset, count;
6238
Joe Perchesb6b38f72010-04-21 03:50:45 +00006239 cFYI(1, "In SetEA");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006240SetEARetry:
6241 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6242 (void **) &pSMBr);
6243 if (rc)
6244 return rc;
6245
6246 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6247 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006248 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
6249 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006250 name_len++; /* trailing null */
6251 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00006252 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006253 name_len = strnlen(fileName, PATH_MAX);
6254 name_len++; /* trailing null */
6255 strncpy(pSMB->FileName, fileName, name_len);
6256 }
6257
6258 params = 6 + name_len;
6259
6260 /* done calculating parms using name_len of file name,
6261 now use name_len to calculate length of ea name
6262 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00006263 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006264 name_len = 0;
6265 else
Steve French50c2f752007-07-13 00:33:32 +00006266 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006267
Steve Frenchdae5dbd2007-12-30 23:49:57 +00006268 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006269 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006270 /* BB find max SMB PDU from sess */
6271 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006272 pSMB->MaxSetupCount = 0;
6273 pSMB->Reserved = 0;
6274 pSMB->Flags = 0;
6275 pSMB->Timeout = 0;
6276 pSMB->Reserved2 = 0;
6277 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006278 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006279 offset = param_offset + params;
6280 pSMB->InformationLevel =
6281 cpu_to_le16(SMB_SET_FILE_EA);
6282
6283 parm_data =
6284 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
6285 offset);
6286 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6287 pSMB->DataOffset = cpu_to_le16(offset);
6288 pSMB->SetupCount = 1;
6289 pSMB->Reserved3 = 0;
6290 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6291 byte_count = 3 /* pad */ + params + count;
6292 pSMB->DataCount = cpu_to_le16(count);
6293 parm_data->list_len = cpu_to_le32(count);
6294 parm_data->list[0].EA_flags = 0;
6295 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08006296 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006297 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00006298 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00006299 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006300 parm_data->list[0].name[name_len] = 0;
6301 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
6302 /* caller ensures that ea_value_len is less than 64K but
6303 we need to ensure that it fits within the smb */
6304
Steve French50c2f752007-07-13 00:33:32 +00006305 /*BB add length check to see if it would fit in
6306 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00006307 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
6308 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00006309 memcpy(parm_data->list[0].name+name_len+1,
6310 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006311
6312 pSMB->TotalDataCount = pSMB->DataCount;
6313 pSMB->ParameterCount = cpu_to_le16(params);
6314 pSMB->TotalParameterCount = pSMB->ParameterCount;
6315 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006316 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006317 pSMB->ByteCount = cpu_to_le16(byte_count);
6318 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6319 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006320 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00006321 cFYI(1, "SetPathInfo (EA) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006322
6323 cifs_buf_release(pSMB);
6324
6325 if (rc == -EAGAIN)
6326 goto SetEARetry;
6327
6328 return rc;
6329}
Linus Torvalds1da177e2005-04-16 15:20:36 -07006330#endif
Steve French0eff0e22011-02-24 05:39:23 +00006331
6332#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */
6333/*
6334 * Years ago the kernel added a "dnotify" function for Samba server,
6335 * to allow network clients (such as Windows) to display updated
6336 * lists of files in directory listings automatically when
6337 * files are added by one user when another user has the
6338 * same directory open on their desktop. The Linux cifs kernel
6339 * client hooked into the kernel side of this interface for
6340 * the same reason, but ironically when the VFS moved from
6341 * "dnotify" to "inotify" it became harder to plug in Linux
6342 * network file system clients (the most obvious use case
6343 * for notify interfaces is when multiple users can update
6344 * the contents of the same directory - exactly what network
6345 * file systems can do) although the server (Samba) could
6346 * still use it. For the short term we leave the worker
6347 * function ifdeffed out (below) until inotify is fixed
6348 * in the VFS to make it easier to plug in network file
6349 * system clients. If inotify turns out to be permanently
6350 * incompatible for network fs clients, we could instead simply
6351 * expose this config flag by adding a future cifs (and smb2) notify ioctl.
6352 */
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006353int CIFSSMBNotify(const unsigned int xid, struct cifs_tcon *tcon,
Steve French0eff0e22011-02-24 05:39:23 +00006354 const int notify_subdirs, const __u16 netfid,
6355 __u32 filter, struct file *pfile, int multishot,
6356 const struct nls_table *nls_codepage)
6357{
6358 int rc = 0;
6359 struct smb_com_transaction_change_notify_req *pSMB = NULL;
6360 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
6361 struct dir_notify_req *dnotify_req;
6362 int bytes_returned;
6363
6364 cFYI(1, "In CIFSSMBNotify for file handle %d", (int)netfid);
6365 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
6366 (void **) &pSMBr);
6367 if (rc)
6368 return rc;
6369
6370 pSMB->TotalParameterCount = 0 ;
6371 pSMB->TotalDataCount = 0;
6372 pSMB->MaxParameterCount = cpu_to_le32(2);
Jeff Laytonc974bef2011-10-11 06:41:32 -04006373 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Steve French0eff0e22011-02-24 05:39:23 +00006374 pSMB->MaxSetupCount = 4;
6375 pSMB->Reserved = 0;
6376 pSMB->ParameterOffset = 0;
6377 pSMB->DataCount = 0;
6378 pSMB->DataOffset = 0;
6379 pSMB->SetupCount = 4; /* single byte does not need le conversion */
6380 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
6381 pSMB->ParameterCount = pSMB->TotalParameterCount;
6382 if (notify_subdirs)
6383 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
6384 pSMB->Reserved2 = 0;
6385 pSMB->CompletionFilter = cpu_to_le32(filter);
6386 pSMB->Fid = netfid; /* file handle always le */
6387 pSMB->ByteCount = 0;
6388
6389 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6390 (struct smb_hdr *)pSMBr, &bytes_returned,
6391 CIFS_ASYNC_OP);
6392 if (rc) {
6393 cFYI(1, "Error in Notify = %d", rc);
6394 } else {
6395 /* Add file to outstanding requests */
6396 /* BB change to kmem cache alloc */
6397 dnotify_req = kmalloc(
6398 sizeof(struct dir_notify_req),
6399 GFP_KERNEL);
6400 if (dnotify_req) {
6401 dnotify_req->Pid = pSMB->hdr.Pid;
6402 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
6403 dnotify_req->Mid = pSMB->hdr.Mid;
6404 dnotify_req->Tid = pSMB->hdr.Tid;
6405 dnotify_req->Uid = pSMB->hdr.Uid;
6406 dnotify_req->netfid = netfid;
6407 dnotify_req->pfile = pfile;
6408 dnotify_req->filter = filter;
6409 dnotify_req->multishot = multishot;
6410 spin_lock(&GlobalMid_Lock);
6411 list_add_tail(&dnotify_req->lhead,
6412 &GlobalDnotifyReqList);
6413 spin_unlock(&GlobalMid_Lock);
6414 } else
6415 rc = -ENOMEM;
6416 }
6417 cifs_buf_release(pSMB);
6418 return rc;
6419}
6420#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */