blob: 83df937b814e0b92bd99020a35e5db8988e4a1c4 [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>
35#include <asm/uaccess.h>
36#include "cifspdu.h"
37#include "cifsglob.h"
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +000038#include "cifsacl.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070039#include "cifsproto.h"
40#include "cifs_unicode.h"
41#include "cifs_debug.h"
42
43#ifdef CONFIG_CIFS_POSIX
44static struct {
45 int index;
46 char *name;
47} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000048#ifdef CONFIG_CIFS_WEAK_PW_HASH
49 {LANMAN_PROT, "\2LM1.2X002"},
Steve French9ac00b72006-09-30 04:13:17 +000050 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000051#endif /* weak password hashing for legacy clients */
Steve French50c2f752007-07-13 00:33:32 +000052 {CIFS_PROT, "\2NT LM 0.12"},
Steve French39798772006-05-31 22:40:51 +000053 {POSIX_PROT, "\2POSIX 2"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070054 {BAD_PROT, "\2"}
55};
56#else
57static struct {
58 int index;
59 char *name;
60} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000061#ifdef CONFIG_CIFS_WEAK_PW_HASH
62 {LANMAN_PROT, "\2LM1.2X002"},
Steve French18f75ca2006-10-01 03:13:01 +000063 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000064#endif /* weak password hashing for legacy clients */
Steve French790fe572007-07-07 19:25:05 +000065 {CIFS_PROT, "\2NT LM 0.12"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070066 {BAD_PROT, "\2"}
67};
68#endif
69
Steve French39798772006-05-31 22:40:51 +000070/* define the number of elements in the cifs dialect array */
71#ifdef CONFIG_CIFS_POSIX
72#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000073#define CIFS_NUM_PROT 4
Steve French39798772006-05-31 22:40:51 +000074#else
75#define CIFS_NUM_PROT 2
76#endif /* CIFS_WEAK_PW_HASH */
77#else /* not posix */
78#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000079#define CIFS_NUM_PROT 3
Steve French39798772006-05-31 22:40:51 +000080#else
81#define CIFS_NUM_PROT 1
82#endif /* CONFIG_CIFS_WEAK_PW_HASH */
83#endif /* CIFS_POSIX */
84
Linus Torvalds1da177e2005-04-16 15:20:36 -070085/* Mark as invalid, all open files on tree connections since they
86 were closed when session to server was lost */
Steve French790fe572007-07-07 19:25:05 +000087static void mark_open_files_invalid(struct cifsTconInfo *pTcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -070088{
89 struct cifsFileInfo *open_file = NULL;
Steve French790fe572007-07-07 19:25:05 +000090 struct list_head *tmp;
91 struct list_head *tmp1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070092
93/* list all files open on tree connection and mark them invalid */
Jeff Layton44772882010-10-15 15:34:03 -040094 spin_lock(&cifs_file_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070095 list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
Steve French790fe572007-07-07 19:25:05 +000096 open_file = list_entry(tmp, struct cifsFileInfo, tlist);
Steve Frenchad8b15f2008-08-08 21:10:16 +000097 open_file->invalidHandle = true;
Jeff Layton3bc303c2009-09-21 06:47:50 -040098 open_file->oplock_break_cancelled = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -070099 }
Jeff Layton44772882010-10-15 15:34:03 -0400100 spin_unlock(&cifs_file_list_lock);
Steve French09d1db52005-04-28 22:41:08 -0700101 /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
102 to this tcon */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103}
104
Jeff Layton9162ab22009-09-03 12:07:17 -0400105/* reconnect the socket, tcon, and smb session if needed */
106static int
107cifs_reconnect_tcon(struct cifsTconInfo *tcon, int smb_command)
108{
109 int rc = 0;
110 struct cifsSesInfo *ses;
111 struct TCP_Server_Info *server;
112 struct nls_table *nls_codepage;
113
114 /*
115 * SMBs NegProt, SessSetup, uLogoff do not have tcon yet so check for
116 * tcp and smb session status done differently for those three - in the
117 * calling routine
118 */
119 if (!tcon)
120 return 0;
121
122 ses = tcon->ses;
123 server = ses->server;
124
125 /*
126 * only tree disconnect, open, and write, (and ulogoff which does not
127 * have tcon) are allowed as we start force umount
128 */
129 if (tcon->tidStatus == CifsExiting) {
130 if (smb_command != SMB_COM_WRITE_ANDX &&
131 smb_command != SMB_COM_OPEN_ANDX &&
132 smb_command != SMB_COM_TREE_DISCONNECT) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000133 cFYI(1, "can not send cmd %d while umounting",
134 smb_command);
Jeff Layton9162ab22009-09-03 12:07:17 -0400135 return -ENODEV;
136 }
137 }
138
Jeff Layton9162ab22009-09-03 12:07:17 -0400139 /*
140 * Give demultiplex thread up to 10 seconds to reconnect, should be
141 * greater than cifs socket timeout which is 7 seconds
142 */
143 while (server->tcpStatus == CifsNeedReconnect) {
144 wait_event_interruptible_timeout(server->response_q,
Steve Frenchfd88ce92011-04-12 01:01:14 +0000145 (server->tcpStatus != CifsNeedReconnect), 10 * HZ);
Jeff Layton9162ab22009-09-03 12:07:17 -0400146
Steve Frenchfd88ce92011-04-12 01:01:14 +0000147 /* are we still trying to reconnect? */
Jeff Layton9162ab22009-09-03 12:07:17 -0400148 if (server->tcpStatus != CifsNeedReconnect)
149 break;
150
151 /*
152 * on "soft" mounts we wait once. Hard mounts keep
153 * retrying until process is killed or server comes
154 * back on-line
155 */
Jeff Laytond4025392011-02-07 08:54:35 -0500156 if (!tcon->retry) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000157 cFYI(1, "gave up waiting on reconnect in smb_init");
Jeff Layton9162ab22009-09-03 12:07:17 -0400158 return -EHOSTDOWN;
159 }
160 }
161
162 if (!ses->need_reconnect && !tcon->need_reconnect)
163 return 0;
164
165 nls_codepage = load_nls_default();
166
167 /*
168 * need to prevent multiple threads trying to simultaneously
169 * reconnect the same SMB session
170 */
Steve Frenchd7b619c2010-02-25 05:36:46 +0000171 mutex_lock(&ses->session_mutex);
Jeff Layton198b5682010-04-24 07:57:48 -0400172 rc = cifs_negotiate_protocol(0, ses);
173 if (rc == 0 && ses->need_reconnect)
Jeff Layton9162ab22009-09-03 12:07:17 -0400174 rc = cifs_setup_session(0, ses, nls_codepage);
175
176 /* do we need to reconnect tcon? */
177 if (rc || !tcon->need_reconnect) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000178 mutex_unlock(&ses->session_mutex);
Jeff Layton9162ab22009-09-03 12:07:17 -0400179 goto out;
180 }
181
182 mark_open_files_invalid(tcon);
183 rc = CIFSTCon(0, ses, tcon->treeName, tcon, nls_codepage);
Steve Frenchd7b619c2010-02-25 05:36:46 +0000184 mutex_unlock(&ses->session_mutex);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000185 cFYI(1, "reconnect tcon rc = %d", rc);
Jeff Layton9162ab22009-09-03 12:07:17 -0400186
187 if (rc)
188 goto out;
189
190 /*
191 * FIXME: check if wsize needs updated due to negotiated smb buffer
192 * size shrinking
193 */
194 atomic_inc(&tconInfoReconnectCount);
195
196 /* tell server Unix caps we support */
197 if (ses->capabilities & CAP_UNIX)
198 reset_cifs_unix_caps(0, tcon, NULL, NULL);
199
200 /*
201 * Removed call to reopen open files here. It is safer (and faster) to
202 * reopen files one at a time as needed in read and write.
203 *
204 * FIXME: what about file locks? don't we need to reclaim them ASAP?
205 */
206
207out:
208 /*
209 * Check if handle based operation so we know whether we can continue
210 * or not without returning to caller to reset file handle
211 */
212 switch (smb_command) {
213 case SMB_COM_READ_ANDX:
214 case SMB_COM_WRITE_ANDX:
215 case SMB_COM_CLOSE:
216 case SMB_COM_FIND_CLOSE2:
217 case SMB_COM_LOCKING_ANDX:
218 rc = -EAGAIN;
219 }
220
221 unload_nls(nls_codepage);
222 return rc;
223}
224
Steve Frenchad7a2922008-02-07 23:25:02 +0000225/* Allocate and return pointer to an SMB request buffer, and set basic
226 SMB information in the SMB header. If the return code is zero, this
227 function must have filled in request_buf pointer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228static int
229small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000230 void **request_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231{
Jeff Laytonf5695992010-09-29 15:27:08 -0400232 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233
Jeff Layton9162ab22009-09-03 12:07:17 -0400234 rc = cifs_reconnect_tcon(tcon, smb_command);
Steve French790fe572007-07-07 19:25:05 +0000235 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 return rc;
237
238 *request_buf = cifs_small_buf_get();
239 if (*request_buf == NULL) {
240 /* BB should we add a retry in here if not a writepage? */
241 return -ENOMEM;
242 }
243
Steve French63135e02007-07-17 17:34:02 +0000244 header_assemble((struct smb_hdr *) *request_buf, smb_command,
Steve Frenchc18c8422007-07-18 23:21:09 +0000245 tcon, wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246
Steve French790fe572007-07-07 19:25:05 +0000247 if (tcon != NULL)
248 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700249
Jeff Laytonf5695992010-09-29 15:27:08 -0400250 return 0;
Steve French5815449d2006-02-14 01:36:20 +0000251}
252
Steve French12b3b8f2006-02-09 21:12:47 +0000253int
Steve French50c2f752007-07-13 00:33:32 +0000254small_smb_init_no_tc(const int smb_command, const int wct,
Steve French5815449d2006-02-14 01:36:20 +0000255 struct cifsSesInfo *ses, void **request_buf)
Steve French12b3b8f2006-02-09 21:12:47 +0000256{
257 int rc;
Steve French50c2f752007-07-13 00:33:32 +0000258 struct smb_hdr *buffer;
Steve French12b3b8f2006-02-09 21:12:47 +0000259
Steve French5815449d2006-02-14 01:36:20 +0000260 rc = small_smb_init(smb_command, wct, NULL, request_buf);
Steve French790fe572007-07-07 19:25:05 +0000261 if (rc)
Steve French12b3b8f2006-02-09 21:12:47 +0000262 return rc;
263
Steve French04fdabe2006-02-10 05:52:50 +0000264 buffer = (struct smb_hdr *)*request_buf;
Steve French12b3b8f2006-02-09 21:12:47 +0000265 buffer->Mid = GetNextMid(ses->server);
266 if (ses->capabilities & CAP_UNICODE)
267 buffer->Flags2 |= SMBFLG2_UNICODE;
Steve French04fdabe2006-02-10 05:52:50 +0000268 if (ses->capabilities & CAP_STATUS32)
Steve French12b3b8f2006-02-09 21:12:47 +0000269 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
270
271 /* uid, tid can stay at zero as set in header assemble */
272
Steve French50c2f752007-07-13 00:33:32 +0000273 /* BB add support for turning on the signing when
Steve French12b3b8f2006-02-09 21:12:47 +0000274 this function is used after 1st of session setup requests */
275
276 return rc;
277}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278
279/* If the return code is zero, this function must fill in request_buf pointer */
280static int
Jeff Laytonf5695992010-09-29 15:27:08 -0400281__smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
282 void **request_buf, void **response_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 *request_buf = cifs_buf_get();
285 if (*request_buf == NULL) {
286 /* BB should we add a retry in here if not a writepage? */
287 return -ENOMEM;
288 }
289 /* Although the original thought was we needed the response buf for */
290 /* potential retries of smb operations it turns out we can determine */
291 /* from the mid flags when the request buffer can be resent without */
292 /* having to use a second distinct buffer for the response */
Steve French790fe572007-07-07 19:25:05 +0000293 if (response_buf)
Steve French50c2f752007-07-13 00:33:32 +0000294 *response_buf = *request_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295
296 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000297 wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298
Steve French790fe572007-07-07 19:25:05 +0000299 if (tcon != NULL)
300 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700301
Jeff Laytonf5695992010-09-29 15:27:08 -0400302 return 0;
303}
304
305/* If the return code is zero, this function must fill in request_buf pointer */
306static int
307smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
308 void **request_buf, void **response_buf)
309{
310 int rc;
311
312 rc = cifs_reconnect_tcon(tcon, smb_command);
313 if (rc)
314 return rc;
315
316 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
317}
318
319static int
320smb_init_no_reconnect(int smb_command, int wct, struct cifsTconInfo *tcon,
321 void **request_buf, void **response_buf)
322{
323 if (tcon->ses->need_reconnect || tcon->need_reconnect)
324 return -EHOSTDOWN;
325
326 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327}
328
Steve French50c2f752007-07-13 00:33:32 +0000329static int validate_t2(struct smb_t2_rsp *pSMB)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330{
Jeff Layton12df83c2011-01-20 13:36:51 -0500331 unsigned int total_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332
Jeff Layton12df83c2011-01-20 13:36:51 -0500333 /* check for plausible wct */
334 if (pSMB->hdr.WordCount < 10)
335 goto vt2_err;
336
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 /* check for parm and data offset going beyond end of smb */
Jeff Layton12df83c2011-01-20 13:36:51 -0500338 if (get_unaligned_le16(&pSMB->t2_rsp.ParameterOffset) > 1024 ||
339 get_unaligned_le16(&pSMB->t2_rsp.DataOffset) > 1024)
340 goto vt2_err;
341
Jeff Layton12df83c2011-01-20 13:36:51 -0500342 total_size = get_unaligned_le16(&pSMB->t2_rsp.ParameterCount);
343 if (total_size >= 512)
344 goto vt2_err;
345
Jeff Laytonfd5707e2011-03-31 17:22:07 -0400346 /* check that bcc is at least as big as parms + data, and that it is
347 * less than negotiated smb buffer
348 */
Jeff Layton12df83c2011-01-20 13:36:51 -0500349 total_size += get_unaligned_le16(&pSMB->t2_rsp.DataCount);
350 if (total_size > get_bcc(&pSMB->hdr) ||
351 total_size >= CIFSMaxBufSize + MAX_CIFS_HDR_SIZE)
352 goto vt2_err;
353
354 return 0;
355vt2_err:
Steve French50c2f752007-07-13 00:33:32 +0000356 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 sizeof(struct smb_t2_rsp) + 16);
Jeff Layton12df83c2011-01-20 13:36:51 -0500358 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359}
Jeff Layton690c5222011-01-20 13:36:51 -0500360
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000361static inline void inc_rfc1001_len(void *pSMB, int count)
362{
363 struct smb_hdr *hdr = (struct smb_hdr *)pSMB;
364
365 be32_add_cpu(&hdr->smb_buf_length, count);
366}
367
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368int
369CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
370{
371 NEGOTIATE_REQ *pSMB;
372 NEGOTIATE_RSP *pSMBr;
373 int rc = 0;
374 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000375 int i;
Steve French50c2f752007-07-13 00:33:32 +0000376 struct TCP_Server_Info *server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 u16 count;
Steve French750d1152006-06-27 06:28:30 +0000378 unsigned int secFlags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379
Steve French790fe572007-07-07 19:25:05 +0000380 if (ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381 server = ses->server;
382 else {
383 rc = -EIO;
384 return rc;
385 }
386 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
387 (void **) &pSMB, (void **) &pSMBr);
388 if (rc)
389 return rc;
Steve French750d1152006-06-27 06:28:30 +0000390
391 /* if any of auth flags (ie not sign or seal) are overriden use them */
Steve French790fe572007-07-07 19:25:05 +0000392 if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
Steve French762e5ab2007-06-28 18:41:42 +0000393 secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
Steve French750d1152006-06-27 06:28:30 +0000394 else /* if override flags set only sign/seal OR them with global auth */
Jeff Layton04912d62010-04-24 07:57:45 -0400395 secFlags = global_secflags | ses->overrideSecFlg;
Steve French750d1152006-06-27 06:28:30 +0000396
Joe Perchesb6b38f72010-04-21 03:50:45 +0000397 cFYI(1, "secFlags 0x%x", secFlags);
Steve Frenchf40c5622006-06-28 00:13:38 +0000398
Steve French1982c342005-08-17 12:38:22 -0700399 pSMB->hdr.Mid = GetNextMid(server);
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000400 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
Steve Frencha0136892007-10-04 20:05:09 +0000401
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000402 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
Steve French254e55e2006-06-04 05:53:15 +0000403 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Steve Frencha0136892007-10-04 20:05:09 +0000404 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000405 cFYI(1, "Kerberos only mechanism, enable extended security");
Steve Frencha0136892007-10-04 20:05:09 +0000406 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Jeff Laytonb4d6fcf2011-01-07 11:30:28 -0500407 } else if ((secFlags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP)
Steve Frenchac683922009-05-06 04:16:04 +0000408 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
409 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_NTLMSSP) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000410 cFYI(1, "NTLMSSP only mechanism, enable extended security");
Steve Frenchac683922009-05-06 04:16:04 +0000411 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
412 }
Steve French50c2f752007-07-13 00:33:32 +0000413
Steve French39798772006-05-31 22:40:51 +0000414 count = 0;
Steve French50c2f752007-07-13 00:33:32 +0000415 for (i = 0; i < CIFS_NUM_PROT; i++) {
Steve French39798772006-05-31 22:40:51 +0000416 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
417 count += strlen(protocols[i].name) + 1;
418 /* null at end of source and target buffers anyway */
419 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000420 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 pSMB->ByteCount = cpu_to_le16(count);
422
423 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
424 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French50c2f752007-07-13 00:33:32 +0000425 if (rc != 0)
Steve French254e55e2006-06-04 05:53:15 +0000426 goto neg_err_exit;
427
Jeff Layton9bf67e52010-04-24 07:57:46 -0400428 server->dialect = le16_to_cpu(pSMBr->DialectIndex);
429 cFYI(1, "Dialect: %d", server->dialect);
Steve French254e55e2006-06-04 05:53:15 +0000430 /* Check wct = 1 error case */
Jeff Layton9bf67e52010-04-24 07:57:46 -0400431 if ((pSMBr->hdr.WordCount < 13) || (server->dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000432 /* core returns wct = 1, but we do not ask for core - otherwise
Steve French50c2f752007-07-13 00:33:32 +0000433 small wct just comes when dialect index is -1 indicating we
Steve French254e55e2006-06-04 05:53:15 +0000434 could not negotiate a common dialect */
435 rc = -EOPNOTSUPP;
436 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000437#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French790fe572007-07-07 19:25:05 +0000438 } else if ((pSMBr->hdr.WordCount == 13)
Jeff Layton9bf67e52010-04-24 07:57:46 -0400439 && ((server->dialect == LANMAN_PROT)
440 || (server->dialect == LANMAN2_PROT))) {
Steve Frenchb815f1e2006-10-02 05:53:29 +0000441 __s16 tmp;
Steve French50c2f752007-07-13 00:33:32 +0000442 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
Steve French254e55e2006-06-04 05:53:15 +0000443
Steve French790fe572007-07-07 19:25:05 +0000444 if ((secFlags & CIFSSEC_MAY_LANMAN) ||
Steve French750d1152006-06-27 06:28:30 +0000445 (secFlags & CIFSSEC_MAY_PLNTXT))
Steve French254e55e2006-06-04 05:53:15 +0000446 server->secType = LANMAN;
447 else {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000448 cERROR(1, "mount failed weak security disabled"
449 " in /proc/fs/cifs/SecurityFlags");
Steve French39798772006-05-31 22:40:51 +0000450 rc = -EOPNOTSUPP;
451 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000452 }
Steve French254e55e2006-06-04 05:53:15 +0000453 server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
454 server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
455 server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
Steve French39798772006-05-31 22:40:51 +0000456 (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve Frencheca6acf2009-02-20 05:43:09 +0000457 server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
Steve French254e55e2006-06-04 05:53:15 +0000458 /* even though we do not use raw we might as well set this
459 accurately, in case we ever find a need for it */
Steve French790fe572007-07-07 19:25:05 +0000460 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
Steve Frencheca6acf2009-02-20 05:43:09 +0000461 server->max_rw = 0xFF00;
Steve French254e55e2006-06-04 05:53:15 +0000462 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
463 } else {
Steve Frencheca6acf2009-02-20 05:43:09 +0000464 server->max_rw = 0;/* do not need to use raw anyway */
Steve French254e55e2006-06-04 05:53:15 +0000465 server->capabilities = CAP_MPX_MODE;
466 }
Steve Frenchb815f1e2006-10-02 05:53:29 +0000467 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
Steve French1a70d652006-10-02 05:59:18 +0000468 if (tmp == -1) {
Steve French25ee4a92006-09-30 00:54:23 +0000469 /* OS/2 often does not set timezone therefore
470 * we must use server time to calc time zone.
Steve Frenchb815f1e2006-10-02 05:53:29 +0000471 * Could deviate slightly from the right zone.
472 * Smallest defined timezone difference is 15 minutes
473 * (i.e. Nepal). Rounding up/down is done to match
474 * this requirement.
Steve French25ee4a92006-09-30 00:54:23 +0000475 */
Steve Frenchb815f1e2006-10-02 05:53:29 +0000476 int val, seconds, remain, result;
Steve French25ee4a92006-09-30 00:54:23 +0000477 struct timespec ts, utc;
478 utc = CURRENT_TIME;
Jeff Laytonc4a2c082009-05-27 09:37:33 -0400479 ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
480 rsp->SrvTime.Time, 0);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000481 cFYI(1, "SrvTime %d sec since 1970 (utc: %d) diff: %d",
Steve French50c2f752007-07-13 00:33:32 +0000482 (int)ts.tv_sec, (int)utc.tv_sec,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000483 (int)(utc.tv_sec - ts.tv_sec));
Steve Frenchb815f1e2006-10-02 05:53:29 +0000484 val = (int)(utc.tv_sec - ts.tv_sec);
Andre Haupt8594c152007-08-30 20:18:41 +0000485 seconds = abs(val);
Steve French947a5062006-10-02 05:55:25 +0000486 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
Steve Frenchb815f1e2006-10-02 05:53:29 +0000487 remain = seconds % MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000488 if (remain >= (MIN_TZ_ADJ / 2))
Steve Frenchb815f1e2006-10-02 05:53:29 +0000489 result += MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000490 if (val < 0)
Steve Frenchad7a2922008-02-07 23:25:02 +0000491 result = -result;
Steve Frenchb815f1e2006-10-02 05:53:29 +0000492 server->timeAdj = result;
Steve French25ee4a92006-09-30 00:54:23 +0000493 } else {
Steve Frenchb815f1e2006-10-02 05:53:29 +0000494 server->timeAdj = (int)tmp;
495 server->timeAdj *= 60; /* also in seconds */
Steve French25ee4a92006-09-30 00:54:23 +0000496 }
Joe Perchesb6b38f72010-04-21 03:50:45 +0000497 cFYI(1, "server->timeAdj: %d seconds", server->timeAdj);
Steve French25ee4a92006-09-30 00:54:23 +0000498
Steve French39798772006-05-31 22:40:51 +0000499
Steve French254e55e2006-06-04 05:53:15 +0000500 /* BB get server time for time conversions and add
Steve French50c2f752007-07-13 00:33:32 +0000501 code to use it and timezone since this is not UTC */
Steve French39798772006-05-31 22:40:51 +0000502
Steve French50c2f752007-07-13 00:33:32 +0000503 if (rsp->EncryptionKeyLength ==
Steve French25ee4a92006-09-30 00:54:23 +0000504 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500505 memcpy(ses->server->cryptkey, rsp->EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000506 CIFS_CRYPTO_KEY_SIZE);
507 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
508 rc = -EIO; /* need cryptkey unless plain text */
509 goto neg_err_exit;
510 }
Steve French39798772006-05-31 22:40:51 +0000511
Steve Frenchf19159d2010-04-21 04:12:10 +0000512 cFYI(1, "LANMAN negotiated");
Steve French254e55e2006-06-04 05:53:15 +0000513 /* we will not end up setting signing flags - as no signing
514 was in LANMAN and server did not return the flags on */
515 goto signing_check;
Steve French7c7b25b2006-06-01 19:20:10 +0000516#else /* weak security disabled */
Steve French790fe572007-07-07 19:25:05 +0000517 } else if (pSMBr->hdr.WordCount == 13) {
Steve Frenchf19159d2010-04-21 04:12:10 +0000518 cERROR(1, "mount failed, cifs module not built "
519 "with CIFS_WEAK_PW_HASH support");
Dan Carpenter8212cf72010-03-15 11:22:26 +0300520 rc = -EOPNOTSUPP;
Steve French7c7b25b2006-06-01 19:20:10 +0000521#endif /* WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000522 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000523 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000524 /* unknown wct */
525 rc = -EOPNOTSUPP;
526 goto neg_err_exit;
527 }
528 /* else wct == 17 NTLM */
529 server->secMode = pSMBr->SecurityMode;
Steve French790fe572007-07-07 19:25:05 +0000530 if ((server->secMode & SECMODE_USER) == 0)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000531 cFYI(1, "share mode security");
Steve French39798772006-05-31 22:40:51 +0000532
Steve French790fe572007-07-07 19:25:05 +0000533 if ((server->secMode & SECMODE_PW_ENCRYPT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000534#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French750d1152006-06-27 06:28:30 +0000535 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000536#endif /* CIFS_WEAK_PW_HASH */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000537 cERROR(1, "Server requests plain text password"
538 " but client support disabled");
Steve French9312f672006-06-04 22:21:07 +0000539
Steve French790fe572007-07-07 19:25:05 +0000540 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
Steve French254e55e2006-06-04 05:53:15 +0000541 server->secType = NTLMv2;
Steve French790fe572007-07-07 19:25:05 +0000542 else if (secFlags & CIFSSEC_MAY_NTLM)
Steve French254e55e2006-06-04 05:53:15 +0000543 server->secType = NTLM;
Steve French790fe572007-07-07 19:25:05 +0000544 else if (secFlags & CIFSSEC_MAY_NTLMV2)
Steve Frenchf40c5622006-06-28 00:13:38 +0000545 server->secType = NTLMv2;
Steve Frencha0136892007-10-04 20:05:09 +0000546 else if (secFlags & CIFSSEC_MAY_KRB5)
547 server->secType = Kerberos;
Steve Frenchac683922009-05-06 04:16:04 +0000548 else if (secFlags & CIFSSEC_MAY_NTLMSSP)
Steve Frenchf46c7232009-06-25 03:04:20 +0000549 server->secType = RawNTLMSSP;
Steve Frencha0136892007-10-04 20:05:09 +0000550 else if (secFlags & CIFSSEC_MAY_LANMAN)
551 server->secType = LANMAN;
Steve Frencha0136892007-10-04 20:05:09 +0000552 else {
553 rc = -EOPNOTSUPP;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000554 cERROR(1, "Invalid security type");
Steve Frencha0136892007-10-04 20:05:09 +0000555 goto neg_err_exit;
556 }
557 /* else ... any others ...? */
Steve French7c7b25b2006-06-01 19:20:10 +0000558
Steve French254e55e2006-06-04 05:53:15 +0000559 /* one byte, so no need to convert this or EncryptionKeyLen from
560 little endian */
561 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
562 /* probably no need to store and check maxvcs */
563 server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve Frencheca6acf2009-02-20 05:43:09 +0000565 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000566 cFYI(DBG2, "Max buf = %d", ses->server->maxBuf);
Steve French254e55e2006-06-04 05:53:15 +0000567 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e2006-10-02 05:53:29 +0000568 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
569 server->timeAdj *= 60;
Steve French254e55e2006-06-04 05:53:15 +0000570 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500571 memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000572 CIFS_CRYPTO_KEY_SIZE);
573 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
574 && (pSMBr->EncryptionKeyLength == 0)) {
575 /* decode security blob */
576 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
577 rc = -EIO; /* no crypt key only if plain text pwd */
578 goto neg_err_exit;
579 }
580
581 /* BB might be helpful to save off the domain of server here */
582
Steve French50c2f752007-07-13 00:33:32 +0000583 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
Steve French254e55e2006-06-04 05:53:15 +0000584 (server->capabilities & CAP_EXTENDED_SECURITY)) {
Jeff Layton820a8032011-05-04 08:05:26 -0400585 count = get_bcc(&pSMBr->hdr);
Jeff Laytone187e442007-10-16 17:10:44 +0000586 if (count < 16) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587 rc = -EIO;
Jeff Laytone187e442007-10-16 17:10:44 +0000588 goto neg_err_exit;
589 }
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530590 spin_lock(&cifs_tcp_ses_lock);
Jeff Laytone7ddee92008-11-14 13:44:38 -0500591 if (server->srv_count > 1) {
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530592 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000593 if (memcmp(server->server_GUID,
594 pSMBr->u.extended_response.
595 GUID, 16) != 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000596 cFYI(1, "server UID changed");
Steve French254e55e2006-06-04 05:53:15 +0000597 memcpy(server->server_GUID,
Jeff Laytone187e442007-10-16 17:10:44 +0000598 pSMBr->u.extended_response.GUID,
599 16);
600 }
Jeff Laytone7ddee92008-11-14 13:44:38 -0500601 } else {
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530602 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000603 memcpy(server->server_GUID,
604 pSMBr->u.extended_response.GUID, 16);
Jeff Laytone7ddee92008-11-14 13:44:38 -0500605 }
Jeff Laytone187e442007-10-16 17:10:44 +0000606
607 if (count == 16) {
608 server->secType = RawNTLMSSP;
Steve French254e55e2006-06-04 05:53:15 +0000609 } else {
610 rc = decode_negTokenInit(pSMBr->u.extended_response.
Jeff Layton26efa0b2010-04-24 07:57:49 -0400611 SecurityBlob, count - 16,
612 server);
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000613 if (rc == 1)
Jeff Laytone5459372007-11-03 05:11:06 +0000614 rc = 0;
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000615 else
Steve French254e55e2006-06-04 05:53:15 +0000616 rc = -EINVAL;
Shirish Pargaonkar2b149f12010-09-18 22:02:18 -0500617 if (server->secType == Kerberos) {
618 if (!server->sec_kerberos &&
619 !server->sec_mskerberos)
620 rc = -EOPNOTSUPP;
621 } else if (server->secType == RawNTLMSSP) {
622 if (!server->sec_ntlmssp)
623 rc = -EOPNOTSUPP;
624 } else
625 rc = -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626 }
Steve French254e55e2006-06-04 05:53:15 +0000627 } else
628 server->capabilities &= ~CAP_EXTENDED_SECURITY;
629
Steve French6344a422006-06-12 04:18:35 +0000630#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French254e55e2006-06-04 05:53:15 +0000631signing_check:
Steve French6344a422006-06-12 04:18:35 +0000632#endif
Steve French762e5ab2007-06-28 18:41:42 +0000633 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
634 /* MUST_SIGN already includes the MAY_SIGN FLAG
635 so if this is zero it means that signing is disabled */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000636 cFYI(1, "Signing disabled");
Steve Frenchabb63d62007-10-18 02:58:40 +0000637 if (server->secMode & SECMODE_SIGN_REQUIRED) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000638 cERROR(1, "Server requires "
Jeff Layton7111d212007-10-16 16:50:25 +0000639 "packet signing to be enabled in "
Joe Perchesb6b38f72010-04-21 03:50:45 +0000640 "/proc/fs/cifs/SecurityFlags.");
Steve Frenchabb63d62007-10-18 02:58:40 +0000641 rc = -EOPNOTSUPP;
642 }
Steve French50c2f752007-07-13 00:33:32 +0000643 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000644 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Steve French762e5ab2007-06-28 18:41:42 +0000645 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
646 /* signing required */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000647 cFYI(1, "Must sign - secFlags 0x%x", secFlags);
Steve French762e5ab2007-06-28 18:41:42 +0000648 if ((server->secMode &
649 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000650 cERROR(1, "signing required but server lacks support");
Jeff38c10a12007-07-06 21:10:07 +0000651 rc = -EOPNOTSUPP;
Steve French762e5ab2007-06-28 18:41:42 +0000652 } else
653 server->secMode |= SECMODE_SIGN_REQUIRED;
654 } else {
655 /* signing optional ie CIFSSEC_MAY_SIGN */
Steve French790fe572007-07-07 19:25:05 +0000656 if ((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
Steve French50c2f752007-07-13 00:33:32 +0000657 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000658 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 }
Steve French50c2f752007-07-13 00:33:32 +0000660
661neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700662 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000663
Joe Perchesb6b38f72010-04-21 03:50:45 +0000664 cFYI(1, "negprot rc %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 return rc;
666}
667
668int
669CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
670{
671 struct smb_hdr *smb_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673
Joe Perchesb6b38f72010-04-21 03:50:45 +0000674 cFYI(1, "In tree disconnect");
Jeff Laytonf1987b42008-11-15 11:12:47 -0500675
676 /* BB: do we need to check this? These should never be NULL. */
677 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
678 return -EIO;
679
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 /*
Jeff Laytonf1987b42008-11-15 11:12:47 -0500681 * No need to return error on this operation if tid invalidated and
682 * closed on server already e.g. due to tcp session crashing. Also,
683 * the tcon is no longer on the list, so no need to take lock before
684 * checking this.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 */
Steve French268875b2009-06-25 00:29:21 +0000686 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
Steve French50c2f752007-07-13 00:33:32 +0000687 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688
Steve French50c2f752007-07-13 00:33:32 +0000689 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700690 (void **)&smb_buffer);
Jeff Laytonf1987b42008-11-15 11:12:47 -0500691 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 return rc;
Steve French133672e2007-11-13 22:41:37 +0000693
694 rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000696 cFYI(1, "Tree disconnect failed %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697
Steve French50c2f752007-07-13 00:33:32 +0000698 /* No need to return error on this operation if tid invalidated and
Jeff Laytonf1987b42008-11-15 11:12:47 -0500699 closed on server already e.g. due to tcp session crashing */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 if (rc == -EAGAIN)
701 rc = 0;
702
703 return rc;
704}
705
Jeff Layton766fdbb2011-01-11 07:24:21 -0500706/*
707 * This is a no-op for now. We're not really interested in the reply, but
708 * rather in the fact that the server sent one and that server->lstrp
709 * gets updated.
710 *
711 * FIXME: maybe we should consider checking that the reply matches request?
712 */
713static void
714cifs_echo_callback(struct mid_q_entry *mid)
715{
716 struct TCP_Server_Info *server = mid->callback_data;
717
718 DeleteMidQEntry(mid);
719 atomic_dec(&server->inFlight);
720 wake_up(&server->request_q);
721}
722
723int
724CIFSSMBEcho(struct TCP_Server_Info *server)
725{
726 ECHO_REQ *smb;
727 int rc = 0;
728
729 cFYI(1, "In echo request");
730
731 rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
732 if (rc)
733 return rc;
734
735 /* set up echo request */
Steve French5443d132011-03-13 05:08:25 +0000736 smb->hdr.Tid = 0xffff;
Jeff Layton99d86c82011-01-20 21:19:25 -0500737 smb->hdr.WordCount = 1;
738 put_unaligned_le16(1, &smb->EchoCount);
Jeff Layton820a8032011-05-04 08:05:26 -0400739 put_bcc(1, &smb->hdr);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500740 smb->Data[0] = 'a';
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000741 inc_rfc1001_len(smb, 3);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500742
743 rc = cifs_call_async(server, (struct smb_hdr *)smb,
744 cifs_echo_callback, server);
745 if (rc)
746 cFYI(1, "Echo request failed: %d", rc);
747
748 cifs_small_buf_release(smb);
749
750 return rc;
751}
752
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753int
754CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
755{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 LOGOFF_ANDX_REQ *pSMB;
757 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758
Joe Perchesb6b38f72010-04-21 03:50:45 +0000759 cFYI(1, "In SMBLogoff for session disconnect");
Jeff Layton14fbf502008-11-14 13:53:46 -0500760
761 /*
762 * BB: do we need to check validity of ses and server? They should
763 * always be valid since we have an active reference. If not, that
764 * should probably be a BUG()
765 */
766 if (!ses || !ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767 return -EIO;
768
Steve Frenchd7b619c2010-02-25 05:36:46 +0000769 mutex_lock(&ses->session_mutex);
Steve French3b795212008-11-13 19:45:32 +0000770 if (ses->need_reconnect)
771 goto session_already_dead; /* no need to send SMBlogoff if uid
772 already closed due to reconnect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
774 if (rc) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000775 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 return rc;
777 }
778
Steve French3b795212008-11-13 19:45:32 +0000779 pSMB->hdr.Mid = GetNextMid(ses->server);
Steve French1982c342005-08-17 12:38:22 -0700780
Steve French3b795212008-11-13 19:45:32 +0000781 if (ses->server->secMode &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
783 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784
785 pSMB->hdr.Uid = ses->Suid;
786
787 pSMB->AndXCommand = 0xFF;
Steve French133672e2007-11-13 22:41:37 +0000788 rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
Steve French3b795212008-11-13 19:45:32 +0000789session_already_dead:
Steve Frenchd7b619c2010-02-25 05:36:46 +0000790 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791
792 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000793 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794 error */
795 if (rc == -EAGAIN)
796 rc = 0;
797 return rc;
798}
799
800int
Steve French2d785a52007-07-15 01:48:57 +0000801CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
802 __u16 type, const struct nls_table *nls_codepage, int remap)
803{
804 TRANSACTION2_SPI_REQ *pSMB = NULL;
805 TRANSACTION2_SPI_RSP *pSMBr = NULL;
806 struct unlink_psx_rq *pRqD;
807 int name_len;
808 int rc = 0;
809 int bytes_returned = 0;
810 __u16 params, param_offset, offset, byte_count;
811
Joe Perchesb6b38f72010-04-21 03:50:45 +0000812 cFYI(1, "In POSIX delete");
Steve French2d785a52007-07-15 01:48:57 +0000813PsxDelete:
814 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
815 (void **) &pSMBr);
816 if (rc)
817 return rc;
818
819 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
820 name_len =
821 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
822 PATH_MAX, nls_codepage, remap);
823 name_len++; /* trailing null */
824 name_len *= 2;
825 } else { /* BB add path length overrun check */
826 name_len = strnlen(fileName, PATH_MAX);
827 name_len++; /* trailing null */
828 strncpy(pSMB->FileName, fileName, name_len);
829 }
830
831 params = 6 + name_len;
832 pSMB->MaxParameterCount = cpu_to_le16(2);
833 pSMB->MaxDataCount = 0; /* BB double check this with jra */
834 pSMB->MaxSetupCount = 0;
835 pSMB->Reserved = 0;
836 pSMB->Flags = 0;
837 pSMB->Timeout = 0;
838 pSMB->Reserved2 = 0;
839 param_offset = offsetof(struct smb_com_transaction2_spi_req,
840 InformationLevel) - 4;
841 offset = param_offset + params;
842
843 /* Setup pointer to Request Data (inode type) */
844 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
845 pRqD->type = cpu_to_le16(type);
846 pSMB->ParameterOffset = cpu_to_le16(param_offset);
847 pSMB->DataOffset = cpu_to_le16(offset);
848 pSMB->SetupCount = 1;
849 pSMB->Reserved3 = 0;
850 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
851 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
852
853 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
854 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
855 pSMB->ParameterCount = cpu_to_le16(params);
856 pSMB->TotalParameterCount = pSMB->ParameterCount;
857 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
858 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000859 inc_rfc1001_len(pSMB, byte_count);
Steve French2d785a52007-07-15 01:48:57 +0000860 pSMB->ByteCount = cpu_to_le16(byte_count);
861 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
862 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000863 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000864 cFYI(1, "Posix delete returned %d", rc);
Steve French2d785a52007-07-15 01:48:57 +0000865 cifs_buf_release(pSMB);
866
867 cifs_stats_inc(&tcon->num_deletes);
868
869 if (rc == -EAGAIN)
870 goto PsxDelete;
871
872 return rc;
873}
874
875int
Steve French737b7582005-04-28 22:41:06 -0700876CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
877 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878{
879 DELETE_FILE_REQ *pSMB = NULL;
880 DELETE_FILE_RSP *pSMBr = NULL;
881 int rc = 0;
882 int bytes_returned;
883 int name_len;
884
885DelFileRetry:
886 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
887 (void **) &pSMBr);
888 if (rc)
889 return rc;
890
891 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
892 name_len =
Steve French50c2f752007-07-13 00:33:32 +0000893 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
Steve French737b7582005-04-28 22:41:06 -0700894 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 name_len++; /* trailing null */
896 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700897 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 name_len = strnlen(fileName, PATH_MAX);
899 name_len++; /* trailing null */
900 strncpy(pSMB->fileName, fileName, name_len);
901 }
902 pSMB->SearchAttributes =
903 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
904 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000905 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 pSMB->ByteCount = cpu_to_le16(name_len + 1);
907 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
908 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700909 cifs_stats_inc(&tcon->num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000910 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000911 cFYI(1, "Error in RMFile = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912
913 cifs_buf_release(pSMB);
914 if (rc == -EAGAIN)
915 goto DelFileRetry;
916
917 return rc;
918}
919
920int
Steve French50c2f752007-07-13 00:33:32 +0000921CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
Steve French737b7582005-04-28 22:41:06 -0700922 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923{
924 DELETE_DIRECTORY_REQ *pSMB = NULL;
925 DELETE_DIRECTORY_RSP *pSMBr = NULL;
926 int rc = 0;
927 int bytes_returned;
928 int name_len;
929
Joe Perchesb6b38f72010-04-21 03:50:45 +0000930 cFYI(1, "In CIFSSMBRmDir");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931RmDirRetry:
932 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
933 (void **) &pSMBr);
934 if (rc)
935 return rc;
936
937 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French737b7582005-04-28 22:41:06 -0700938 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
939 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 name_len++; /* trailing null */
941 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700942 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943 name_len = strnlen(dirName, PATH_MAX);
944 name_len++; /* trailing null */
945 strncpy(pSMB->DirName, dirName, name_len);
946 }
947
948 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000949 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950 pSMB->ByteCount = cpu_to_le16(name_len + 1);
951 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
952 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700953 cifs_stats_inc(&tcon->num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000954 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000955 cFYI(1, "Error in RMDir = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956
957 cifs_buf_release(pSMB);
958 if (rc == -EAGAIN)
959 goto RmDirRetry;
960 return rc;
961}
962
963int
964CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -0700965 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966{
967 int rc = 0;
968 CREATE_DIRECTORY_REQ *pSMB = NULL;
969 CREATE_DIRECTORY_RSP *pSMBr = NULL;
970 int bytes_returned;
971 int name_len;
972
Joe Perchesb6b38f72010-04-21 03:50:45 +0000973 cFYI(1, "In CIFSSMBMkDir");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974MkDirRetry:
975 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
976 (void **) &pSMBr);
977 if (rc)
978 return rc;
979
980 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +0000981 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
Steve French737b7582005-04-28 22:41:06 -0700982 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 name_len++; /* trailing null */
984 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700985 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 name_len = strnlen(name, PATH_MAX);
987 name_len++; /* trailing null */
988 strncpy(pSMB->DirName, name, name_len);
989 }
990
991 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000992 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993 pSMB->ByteCount = cpu_to_le16(name_len + 1);
994 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
995 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700996 cifs_stats_inc(&tcon->num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000997 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000998 cFYI(1, "Error in Mkdir = %d", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -0700999
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000 cifs_buf_release(pSMB);
1001 if (rc == -EAGAIN)
1002 goto MkDirRetry;
1003 return rc;
1004}
1005
Steve French2dd29d32007-04-23 22:07:35 +00001006int
1007CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
Steve Frenchad7a2922008-02-07 23:25:02 +00001008 __u64 mode, __u16 *netfid, FILE_UNIX_BASIC_INFO *pRetData,
Steve French50c2f752007-07-13 00:33:32 +00001009 __u32 *pOplock, const char *name,
Steve French2dd29d32007-04-23 22:07:35 +00001010 const struct nls_table *nls_codepage, int remap)
1011{
1012 TRANSACTION2_SPI_REQ *pSMB = NULL;
1013 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1014 int name_len;
1015 int rc = 0;
1016 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001017 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +00001018 OPEN_PSX_REQ *pdata;
1019 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +00001020
Joe Perchesb6b38f72010-04-21 03:50:45 +00001021 cFYI(1, "In POSIX Create");
Steve French2dd29d32007-04-23 22:07:35 +00001022PsxCreat:
1023 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1024 (void **) &pSMBr);
1025 if (rc)
1026 return rc;
1027
1028 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1029 name_len =
1030 cifsConvertToUCS((__le16 *) pSMB->FileName, name,
1031 PATH_MAX, nls_codepage, remap);
1032 name_len++; /* trailing null */
1033 name_len *= 2;
1034 } else { /* BB improve the check for buffer overruns BB */
1035 name_len = strnlen(name, PATH_MAX);
1036 name_len++; /* trailing null */
1037 strncpy(pSMB->FileName, name, name_len);
1038 }
1039
1040 params = 6 + name_len;
1041 count = sizeof(OPEN_PSX_REQ);
1042 pSMB->MaxParameterCount = cpu_to_le16(2);
1043 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1044 pSMB->MaxSetupCount = 0;
1045 pSMB->Reserved = 0;
1046 pSMB->Flags = 0;
1047 pSMB->Timeout = 0;
1048 pSMB->Reserved2 = 0;
1049 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001050 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001051 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001052 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001053 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001054 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001055 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001056 pdata->OpenFlags = cpu_to_le32(*pOplock);
1057 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1058 pSMB->DataOffset = cpu_to_le16(offset);
1059 pSMB->SetupCount = 1;
1060 pSMB->Reserved3 = 0;
1061 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1062 byte_count = 3 /* pad */ + params + count;
1063
1064 pSMB->DataCount = cpu_to_le16(count);
1065 pSMB->ParameterCount = cpu_to_le16(params);
1066 pSMB->TotalDataCount = pSMB->DataCount;
1067 pSMB->TotalParameterCount = pSMB->ParameterCount;
1068 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1069 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001070 inc_rfc1001_len(pSMB, byte_count);
Steve French2dd29d32007-04-23 22:07:35 +00001071 pSMB->ByteCount = cpu_to_le16(byte_count);
1072 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1073 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1074 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001075 cFYI(1, "Posix create returned %d", rc);
Steve French2dd29d32007-04-23 22:07:35 +00001076 goto psx_create_err;
1077 }
1078
Joe Perchesb6b38f72010-04-21 03:50:45 +00001079 cFYI(1, "copying inode info");
Steve French2dd29d32007-04-23 22:07:35 +00001080 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1081
Jeff Layton820a8032011-05-04 08:05:26 -04001082 if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) {
Steve French2dd29d32007-04-23 22:07:35 +00001083 rc = -EIO; /* bad smb */
1084 goto psx_create_err;
1085 }
1086
1087 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001088 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001089 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001090
Steve French2dd29d32007-04-23 22:07:35 +00001091 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001092 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001093 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1094 /* Let caller know file was created so we can set the mode. */
1095 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001096 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001097 *pOplock |= CIFS_CREATE_ACTION;
1098 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001099 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1100 pRetData->Type = cpu_to_le32(-1); /* unknown */
Joe Perchesb6b38f72010-04-21 03:50:45 +00001101 cFYI(DBG2, "unknown type");
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001102 } else {
Jeff Layton820a8032011-05-04 08:05:26 -04001103 if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001104 + sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001105 cERROR(1, "Open response data too small");
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001106 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001107 goto psx_create_err;
1108 }
Steve French50c2f752007-07-13 00:33:32 +00001109 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001110 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001111 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001112 }
Steve French2dd29d32007-04-23 22:07:35 +00001113
1114psx_create_err:
1115 cifs_buf_release(pSMB);
1116
Steve French65bc98b2009-07-10 15:27:25 +00001117 if (posix_flags & SMB_O_DIRECTORY)
1118 cifs_stats_inc(&tcon->num_posixmkdirs);
1119 else
1120 cifs_stats_inc(&tcon->num_posixopens);
Steve French2dd29d32007-04-23 22:07:35 +00001121
1122 if (rc == -EAGAIN)
1123 goto PsxCreat;
1124
Steve French50c2f752007-07-13 00:33:32 +00001125 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001126}
1127
Steve Frencha9d02ad2005-08-24 23:06:05 -07001128static __u16 convert_disposition(int disposition)
1129{
1130 __u16 ofun = 0;
1131
1132 switch (disposition) {
1133 case FILE_SUPERSEDE:
1134 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1135 break;
1136 case FILE_OPEN:
1137 ofun = SMBOPEN_OAPPEND;
1138 break;
1139 case FILE_CREATE:
1140 ofun = SMBOPEN_OCREATE;
1141 break;
1142 case FILE_OPEN_IF:
1143 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1144 break;
1145 case FILE_OVERWRITE:
1146 ofun = SMBOPEN_OTRUNC;
1147 break;
1148 case FILE_OVERWRITE_IF:
1149 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1150 break;
1151 default:
Joe Perchesb6b38f72010-04-21 03:50:45 +00001152 cFYI(1, "unknown disposition %d", disposition);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001153 ofun = SMBOPEN_OAPPEND; /* regular open */
1154 }
1155 return ofun;
1156}
1157
Jeff Layton35fc37d2008-05-14 10:22:03 -07001158static int
1159access_flags_to_smbopen_mode(const int access_flags)
1160{
1161 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1162
1163 if (masked_flags == GENERIC_READ)
1164 return SMBOPEN_READ;
1165 else if (masked_flags == GENERIC_WRITE)
1166 return SMBOPEN_WRITE;
1167
1168 /* just go for read/write */
1169 return SMBOPEN_READWRITE;
1170}
1171
Steve Frencha9d02ad2005-08-24 23:06:05 -07001172int
1173SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
1174 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001175 const int access_flags, const int create_options, __u16 *netfid,
1176 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001177 const struct nls_table *nls_codepage, int remap)
1178{
1179 int rc = -EACCES;
1180 OPENX_REQ *pSMB = NULL;
1181 OPENX_RSP *pSMBr = NULL;
1182 int bytes_returned;
1183 int name_len;
1184 __u16 count;
1185
1186OldOpenRetry:
1187 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1188 (void **) &pSMBr);
1189 if (rc)
1190 return rc;
1191
1192 pSMB->AndXCommand = 0xFF; /* none */
1193
1194 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1195 count = 1; /* account for one byte pad to word boundary */
1196 name_len =
1197 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1198 fileName, PATH_MAX, nls_codepage, remap);
1199 name_len++; /* trailing null */
1200 name_len *= 2;
1201 } else { /* BB improve check for buffer overruns BB */
1202 count = 0; /* no pad */
1203 name_len = strnlen(fileName, PATH_MAX);
1204 name_len++; /* trailing null */
1205 strncpy(pSMB->fileName, fileName, name_len);
1206 }
1207 if (*pOplock & REQ_OPLOCK)
1208 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001209 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001210 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001211
Steve Frencha9d02ad2005-08-24 23:06:05 -07001212 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001213 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001214 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1215 /* set file as system file if special file such
1216 as fifo and server expecting SFU style and
1217 no Unix extensions */
1218
Steve French790fe572007-07-07 19:25:05 +00001219 if (create_options & CREATE_OPTION_SPECIAL)
1220 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001221 else /* BB FIXME BB */
1222 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001223
Jeff Layton67750fb2008-05-09 22:28:02 +00001224 if (create_options & CREATE_OPTION_READONLY)
1225 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001226
1227 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001228/* pSMB->CreateOptions = cpu_to_le32(create_options &
1229 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001230 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001231
1232 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001233 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001234 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001235 inc_rfc1001_len(pSMB, count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001236
1237 pSMB->ByteCount = cpu_to_le16(count);
1238 /* long_op set to 1 to allow for oplock break timeouts */
1239 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001240 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001241 cifs_stats_inc(&tcon->num_opens);
1242 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001243 cFYI(1, "Error in Open = %d", rc);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001244 } else {
1245 /* BB verify if wct == 15 */
1246
Steve French582d21e2008-05-13 04:54:12 +00001247/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001248
1249 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1250 /* Let caller know file was created so we can set the mode. */
1251 /* Do we care about the CreateAction in any other cases? */
1252 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001253/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001254 *pOplock |= CIFS_CREATE_ACTION; */
1255 /* BB FIXME END */
1256
Steve French790fe572007-07-07 19:25:05 +00001257 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001258 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1259 pfile_info->LastAccessTime = 0; /* BB fixme */
1260 pfile_info->LastWriteTime = 0; /* BB fixme */
1261 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001262 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001263 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001264 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001265 pfile_info->AllocationSize =
1266 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1267 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001268 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001269 pfile_info->DeletePending = 0;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001270 }
1271 }
1272
1273 cifs_buf_release(pSMB);
1274 if (rc == -EAGAIN)
1275 goto OldOpenRetry;
1276 return rc;
1277}
1278
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279int
1280CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1281 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001282 const int access_flags, const int create_options, __u16 *netfid,
1283 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001284 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001285{
1286 int rc = -EACCES;
1287 OPEN_REQ *pSMB = NULL;
1288 OPEN_RSP *pSMBr = NULL;
1289 int bytes_returned;
1290 int name_len;
1291 __u16 count;
1292
1293openRetry:
1294 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1295 (void **) &pSMBr);
1296 if (rc)
1297 return rc;
1298
1299 pSMB->AndXCommand = 0xFF; /* none */
1300
1301 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1302 count = 1; /* account for one byte pad to word boundary */
1303 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001304 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -07001305 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306 name_len++; /* trailing null */
1307 name_len *= 2;
1308 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001309 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001310 count = 0; /* no pad */
1311 name_len = strnlen(fileName, PATH_MAX);
1312 name_len++; /* trailing null */
1313 pSMB->NameLength = cpu_to_le16(name_len);
1314 strncpy(pSMB->fileName, fileName, name_len);
1315 }
1316 if (*pOplock & REQ_OPLOCK)
1317 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001318 else if (*pOplock & REQ_BATCHOPLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1321 pSMB->AllocationSize = 0;
Steve Frencheda3c022005-07-21 15:20:28 -07001322 /* set file as system file if special file such
1323 as fifo and server expecting SFU style and
1324 no Unix extensions */
Steve French790fe572007-07-07 19:25:05 +00001325 if (create_options & CREATE_OPTION_SPECIAL)
Steve Frencheda3c022005-07-21 15:20:28 -07001326 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1327 else
1328 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Jeff Layton67750fb2008-05-09 22:28:02 +00001329
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330 /* XP does not handle ATTR_POSIX_SEMANTICS */
1331 /* but it helps speed up case sensitive checks for other
1332 servers such as Samba */
1333 if (tcon->ses->capabilities & CAP_UNIX)
1334 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1335
Jeff Layton67750fb2008-05-09 22:28:02 +00001336 if (create_options & CREATE_OPTION_READONLY)
1337 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1338
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1340 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c022005-07-21 15:20:28 -07001341 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001342 /* BB Expirement with various impersonation levels and verify */
1343 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344 pSMB->SecurityFlags =
1345 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1346
1347 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001348 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349
1350 pSMB->ByteCount = cpu_to_le16(count);
1351 /* long_op set to 1 to allow for oplock break timeouts */
1352 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001353 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001354 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001356 cFYI(1, "Error in Open = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357 } else {
Steve French09d1db52005-04-28 22:41:08 -07001358 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1360 /* Let caller know file was created so we can set the mode. */
1361 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001362 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve French50c2f752007-07-13 00:33:32 +00001363 *pOplock |= CIFS_CREATE_ACTION;
Steve French790fe572007-07-07 19:25:05 +00001364 if (pfile_info) {
Steve French61e74802008-12-03 00:57:54 +00001365 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1366 36 /* CreationTime to Attributes */);
1367 /* the file_info buf is endian converted by caller */
1368 pfile_info->AllocationSize = pSMBr->AllocationSize;
1369 pfile_info->EndOfFile = pSMBr->EndOfFile;
1370 pfile_info->NumberOfLinks = cpu_to_le32(1);
1371 pfile_info->DeletePending = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001374
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375 cifs_buf_release(pSMB);
1376 if (rc == -EAGAIN)
1377 goto openRetry;
1378 return rc;
1379}
1380
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381int
Steve French50c2f752007-07-13 00:33:32 +00001382CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
1383 const unsigned int count, const __u64 lseek, unsigned int *nbytes,
1384 char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385{
1386 int rc = -EACCES;
1387 READ_REQ *pSMB = NULL;
1388 READ_RSP *pSMBr = NULL;
1389 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001390 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001391 int resp_buf_type = 0;
1392 struct kvec iov[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393
Joe Perchesb6b38f72010-04-21 03:50:45 +00001394 cFYI(1, "Reading %d bytes on fid %d", count, netfid);
Steve French790fe572007-07-07 19:25:05 +00001395 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001396 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001397 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001398 wct = 10; /* old style read */
Steve French4c3130e2008-12-09 00:28:16 +00001399 if ((lseek >> 32) > 0) {
1400 /* can not handle this big offset for old */
1401 return -EIO;
1402 }
1403 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404
1405 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001406 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407 if (rc)
1408 return rc;
1409
1410 /* tcon and ses pointer are checked in smb_init */
1411 if (tcon->ses->server == NULL)
1412 return -ECONNABORTED;
1413
Steve Frenchec637e32005-12-12 20:53:18 -08001414 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415 pSMB->Fid = netfid;
1416 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001417 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001418 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001419
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420 pSMB->Remaining = 0;
1421 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1422 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001423 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001424 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1425 else {
1426 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001427 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001428 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001429 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001430 }
Steve Frenchec637e32005-12-12 20:53:18 -08001431
1432 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001433 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve Frencha761ac52007-10-18 21:45:27 +00001434 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Jeff Layton77499812011-01-11 07:24:23 -05001435 &resp_buf_type, CIFS_LOG_ERROR);
Steve Frencha4544342005-08-24 13:59:35 -07001436 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001437 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001439 cERROR(1, "Send error in read = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001440 } else {
1441 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1442 data_length = data_length << 16;
1443 data_length += le16_to_cpu(pSMBr->DataLength);
1444 *nbytes = data_length;
1445
1446 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001447 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448 || (data_length > count)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001449 cFYI(1, "bad length %d for count %d",
1450 data_length, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451 rc = -EIO;
1452 *nbytes = 0;
1453 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001454 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001455 le16_to_cpu(pSMBr->DataOffset);
1456/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001457 cERROR(1, "Faulting on read rc = %d",rc);
Steve French50c2f752007-07-13 00:33:32 +00001458 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001459 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001460 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001461 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462 }
1463 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464
Steve French4b8f9302006-02-26 16:41:18 +00001465/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001466 if (*buf) {
1467 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001468 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001469 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001470 cifs_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001471 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001472 /* return buffer to caller to free */
1473 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001474 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001475 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001476 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001477 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001478 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001479
1480 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001481 since file handle passed in no longer valid */
1482 return rc;
1483}
1484
Steve Frenchec637e32005-12-12 20:53:18 -08001485
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486int
1487CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1488 const int netfid, const unsigned int count,
1489 const __u64 offset, unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001490 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491{
1492 int rc = -EACCES;
1493 WRITE_REQ *pSMB = NULL;
1494 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001495 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496 __u32 bytes_sent;
1497 __u16 byte_count;
1498
Steve Frencha24e2d72010-04-03 17:20:21 +00001499 *nbytes = 0;
1500
Joe Perchesb6b38f72010-04-21 03:50:45 +00001501 /* cFYI(1, "write at %lld %d bytes", offset, count);*/
Steve French790fe572007-07-07 19:25:05 +00001502 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001503 return -ECONNABORTED;
1504
Steve French790fe572007-07-07 19:25:05 +00001505 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001506 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001507 else {
Steve French1c955182005-08-30 20:58:07 -07001508 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001509 if ((offset >> 32) > 0) {
1510 /* can not handle big offset for old srv */
1511 return -EIO;
1512 }
1513 }
Steve French1c955182005-08-30 20:58:07 -07001514
1515 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516 (void **) &pSMBr);
1517 if (rc)
1518 return rc;
1519 /* tcon and ses pointer are checked in smb_init */
1520 if (tcon->ses->server == NULL)
1521 return -ECONNABORTED;
1522
1523 pSMB->AndXCommand = 0xFF; /* none */
1524 pSMB->Fid = netfid;
1525 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001526 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001527 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001528
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529 pSMB->Reserved = 0xFFFFFFFF;
1530 pSMB->WriteMode = 0;
1531 pSMB->Remaining = 0;
1532
Steve French50c2f752007-07-13 00:33:32 +00001533 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534 can send more if LARGE_WRITE_X capability returned by the server and if
1535 our buffer is big enough or if we convert to iovecs on socket writes
1536 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001537 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1539 } else {
1540 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1541 & ~0xFF;
1542 }
1543
1544 if (bytes_sent > count)
1545 bytes_sent = count;
1546 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001547 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001548 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001549 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001550 else if (ubuf) {
1551 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552 cifs_buf_release(pSMB);
1553 return -EFAULT;
1554 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001555 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556 /* No buffer */
1557 cifs_buf_release(pSMB);
1558 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001559 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001560 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001561 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001562 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001563 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001564
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1566 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001567 inc_rfc1001_len(pSMB, byte_count);
Steve French1c955182005-08-30 20:58:07 -07001568
Steve French790fe572007-07-07 19:25:05 +00001569 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001570 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001571 else { /* old style write has byte count 4 bytes earlier
1572 so 4 bytes pad */
1573 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001574 (struct smb_com_writex_req *)pSMB;
1575 pSMBW->ByteCount = cpu_to_le16(byte_count);
1576 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577
1578 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1579 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001580 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00001582 cFYI(1, "Send error in write = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583 } else {
1584 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1585 *nbytes = (*nbytes) << 16;
1586 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301587
1588 /*
1589 * Mask off high 16 bits when bytes written as returned by the
1590 * server is greater than bytes requested by the client. Some
1591 * OS/2 servers are known to set incorrect CountHigh values.
1592 */
1593 if (*nbytes > count)
1594 *nbytes &= 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595 }
1596
1597 cifs_buf_release(pSMB);
1598
Steve French50c2f752007-07-13 00:33:32 +00001599 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001600 since file handle passed in no longer valid */
1601
1602 return rc;
1603}
1604
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001605int
1606CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607 const int netfid, const unsigned int count,
Steve French3e844692005-10-03 13:37:24 -07001608 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1609 int n_vec, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610{
1611 int rc = -EACCES;
1612 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001613 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001614 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001615 int resp_buf_type = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001617 *nbytes = 0;
1618
Joe Perchesb6b38f72010-04-21 03:50:45 +00001619 cFYI(1, "write2 at %lld %d bytes", (long long)offset, count);
Steve Frenchff7feac2005-11-15 16:45:16 -08001620
Steve French4c3130e2008-12-09 00:28:16 +00001621 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07001622 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001623 } else {
Steve French8cc64c62005-10-03 13:49:43 -07001624 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001625 if ((offset >> 32) > 0) {
1626 /* can not handle big offset for old srv */
1627 return -EIO;
1628 }
1629 }
Steve French8cc64c62005-10-03 13:49:43 -07001630 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631 if (rc)
1632 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633 /* tcon and ses pointer are checked in smb_init */
1634 if (tcon->ses->server == NULL)
1635 return -ECONNABORTED;
1636
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001637 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638 pSMB->Fid = netfid;
1639 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001640 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001641 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642 pSMB->Reserved = 0xFFFFFFFF;
1643 pSMB->WriteMode = 0;
1644 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001645
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001647 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001648
Steve French3e844692005-10-03 13:37:24 -07001649 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1650 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001651 /* header + 1 byte pad */
1652 smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
Steve French790fe572007-07-07 19:25:05 +00001653 if (wct == 14)
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001654 inc_rfc1001_len(pSMB, count + 1);
Steve French8cc64c62005-10-03 13:49:43 -07001655 else /* wct == 12 */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001656 inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
Steve French790fe572007-07-07 19:25:05 +00001657 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001658 pSMB->ByteCount = cpu_to_le16(count + 1);
1659 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00001660 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07001661 (struct smb_com_writex_req *)pSMB;
1662 pSMBW->ByteCount = cpu_to_le16(count + 5);
1663 }
Steve French3e844692005-10-03 13:37:24 -07001664 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00001665 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08001666 iov[0].iov_len = smb_hdr_len + 4;
1667 else /* wct == 12 pad bigger by four bytes */
1668 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00001669
Steve French3e844692005-10-03 13:37:24 -07001670
Steve Frenchec637e32005-12-12 20:53:18 -08001671 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French133672e2007-11-13 22:41:37 +00001672 long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001673 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001675 cFYI(1, "Send error Write2 = %d", rc);
Steve French790fe572007-07-07 19:25:05 +00001676 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08001677 /* presumably this can not happen, but best to be safe */
1678 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001679 } else {
Steve Frenchad7a2922008-02-07 23:25:02 +00001680 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001681 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1682 *nbytes = (*nbytes) << 16;
1683 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301684
1685 /*
1686 * Mask off high 16 bits when bytes written as returned by the
1687 * server is greater than bytes requested by the client. OS/2
1688 * servers are known to set incorrect CountHigh values.
1689 */
1690 if (*nbytes > count)
1691 *nbytes &= 0xFFFF;
Steve French50c2f752007-07-13 00:33:32 +00001692 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693
Steve French4b8f9302006-02-26 16:41:18 +00001694/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001695 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001696 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001697 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001698 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699
Steve French50c2f752007-07-13 00:33:32 +00001700 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701 since file handle passed in no longer valid */
1702
1703 return rc;
1704}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001705
1706
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707int
1708CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1709 const __u16 smb_file_id, const __u64 len,
1710 const __u64 offset, const __u32 numUnlock,
Pavel Shilovsky12fed002011-01-17 20:15:44 +03001711 const __u32 numLock, const __u8 lockType,
1712 const bool waitFlag, const __u8 oplock_level)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713{
1714 int rc = 0;
1715 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00001716/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717 int bytes_returned;
1718 int timeout = 0;
1719 __u16 count;
1720
Joe Perchesb6b38f72010-04-21 03:50:45 +00001721 cFYI(1, "CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock);
Steve French46810cb2005-04-28 22:41:09 -07001722 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1723
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724 if (rc)
1725 return rc;
1726
Steve French790fe572007-07-07 19:25:05 +00001727 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Steve French133672e2007-11-13 22:41:37 +00001728 timeout = CIFS_ASYNC_OP; /* no response expected */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00001730 } else if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00001731 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1733 } else {
1734 pSMB->Timeout = 0;
1735 }
1736
1737 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1738 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1739 pSMB->LockType = lockType;
Pavel Shilovsky12fed002011-01-17 20:15:44 +03001740 pSMB->OplockLevel = oplock_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741 pSMB->AndXCommand = 0xFF; /* none */
1742 pSMB->Fid = smb_file_id; /* netfid stays le */
1743
Steve French790fe572007-07-07 19:25:05 +00001744 if ((numLock != 0) || (numUnlock != 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1746 /* BB where to store pid high? */
1747 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1748 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1749 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1750 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1751 count = sizeof(LOCKING_ANDX_RANGE);
1752 } else {
1753 /* oplock break */
1754 count = 0;
1755 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001756 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757 pSMB->ByteCount = cpu_to_le16(count);
1758
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001759 if (waitFlag) {
1760 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00001761 (struct smb_hdr *) pSMB, &bytes_returned);
Steve French133672e2007-11-13 22:41:37 +00001762 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001763 } else {
Steve French133672e2007-11-13 22:41:37 +00001764 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
1765 timeout);
1766 /* SMB buffer freed by function above */
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001767 }
Steve Frencha4544342005-08-24 13:59:35 -07001768 cifs_stats_inc(&tcon->num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00001769 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001770 cFYI(1, "Send error in Lock = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771
Steve French50c2f752007-07-13 00:33:32 +00001772 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773 since file handle passed in no longer valid */
1774 return rc;
1775}
1776
1777int
Steve French08547b02006-02-28 22:39:25 +00001778CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1779 const __u16 smb_file_id, const int get_flag, const __u64 len,
Steve French50c2f752007-07-13 00:33:32 +00001780 struct file_lock *pLockData, const __u16 lock_type,
Steve French4b18f2a2008-04-29 00:06:05 +00001781 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00001782{
1783 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1784 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00001785 struct cifs_posix_lock *parm_data;
1786 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00001787 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00001788 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00001789 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00001790 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00001791 struct kvec iov[1];
Steve French08547b02006-02-28 22:39:25 +00001792
Joe Perchesb6b38f72010-04-21 03:50:45 +00001793 cFYI(1, "Posix Lock");
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001794
Steve French790fe572007-07-07 19:25:05 +00001795 if (pLockData == NULL)
Marcin Slusarzed5f0372008-05-13 04:01:01 +00001796 return -EINVAL;
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001797
Steve French08547b02006-02-28 22:39:25 +00001798 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1799
1800 if (rc)
1801 return rc;
1802
1803 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1804
Steve French50c2f752007-07-13 00:33:32 +00001805 params = 6;
Steve French08547b02006-02-28 22:39:25 +00001806 pSMB->MaxSetupCount = 0;
1807 pSMB->Reserved = 0;
1808 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00001809 pSMB->Reserved2 = 0;
1810 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1811 offset = param_offset + params;
1812
Steve French08547b02006-02-28 22:39:25 +00001813 count = sizeof(struct cifs_posix_lock);
1814 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00001815 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00001816 pSMB->SetupCount = 1;
1817 pSMB->Reserved3 = 0;
Steve French790fe572007-07-07 19:25:05 +00001818 if (get_flag)
Steve French08547b02006-02-28 22:39:25 +00001819 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1820 else
1821 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1822 byte_count = 3 /* pad */ + params + count;
1823 pSMB->DataCount = cpu_to_le16(count);
1824 pSMB->ParameterCount = cpu_to_le16(params);
1825 pSMB->TotalDataCount = pSMB->DataCount;
1826 pSMB->TotalParameterCount = pSMB->ParameterCount;
1827 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00001828 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00001829 (((char *) &pSMB->hdr.Protocol) + offset);
1830
1831 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00001832 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00001833 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00001834 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00001835 pSMB->Timeout = cpu_to_le32(-1);
1836 } else
1837 pSMB->Timeout = 0;
1838
Steve French08547b02006-02-28 22:39:25 +00001839 parm_data->pid = cpu_to_le32(current->tgid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001840 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00001841 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00001842
1843 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00001844 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00001845 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1846 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001847 inc_rfc1001_len(pSMB, byte_count);
Steve French08547b02006-02-28 22:39:25 +00001848 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001849 if (waitFlag) {
1850 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1851 (struct smb_hdr *) pSMBr, &bytes_returned);
1852 } else {
Steve French133672e2007-11-13 22:41:37 +00001853 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001854 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French133672e2007-11-13 22:41:37 +00001855 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1856 &resp_buf_type, timeout);
1857 pSMB = NULL; /* request buf already freed by SendReceive2. Do
1858 not try to free it twice below on exit */
1859 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001860 }
1861
Steve French08547b02006-02-28 22:39:25 +00001862 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001863 cFYI(1, "Send error in Posix Lock = %d", rc);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001864 } else if (get_flag) {
1865 /* lock structure can be returned on get */
1866 __u16 data_offset;
1867 __u16 data_count;
1868 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00001869
Jeff Layton820a8032011-05-04 08:05:26 -04001870 if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001871 rc = -EIO; /* bad smb */
1872 goto plk_err_exit;
1873 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001874 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1875 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00001876 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001877 rc = -EIO;
1878 goto plk_err_exit;
1879 }
1880 parm_data = (struct cifs_posix_lock *)
1881 ((char *)&pSMBr->hdr.Protocol + data_offset);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04001882 if (parm_data->lock_type == __constant_cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001883 pLockData->fl_type = F_UNLCK;
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04001884 else {
1885 if (parm_data->lock_type ==
1886 __constant_cpu_to_le16(CIFS_RDLCK))
1887 pLockData->fl_type = F_RDLCK;
1888 else if (parm_data->lock_type ==
1889 __constant_cpu_to_le16(CIFS_WRLCK))
1890 pLockData->fl_type = F_WRLCK;
1891
Steve French5443d132011-03-13 05:08:25 +00001892 pLockData->fl_start = le64_to_cpu(parm_data->start);
1893 pLockData->fl_end = pLockData->fl_start +
1894 le64_to_cpu(parm_data->length) - 1;
1895 pLockData->fl_pid = le32_to_cpu(parm_data->pid);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04001896 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001897 }
Steve French50c2f752007-07-13 00:33:32 +00001898
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001899plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00001900 if (pSMB)
1901 cifs_small_buf_release(pSMB);
1902
Steve French133672e2007-11-13 22:41:37 +00001903 if (resp_buf_type == CIFS_SMALL_BUFFER)
1904 cifs_small_buf_release(iov[0].iov_base);
1905 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1906 cifs_buf_release(iov[0].iov_base);
1907
Steve French08547b02006-02-28 22:39:25 +00001908 /* Note: On -EAGAIN error only caller can retry on handle based calls
1909 since file handle passed in no longer valid */
1910
1911 return rc;
1912}
1913
1914
1915int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001916CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1917{
1918 int rc = 0;
1919 CLOSE_REQ *pSMB = NULL;
Joe Perchesb6b38f72010-04-21 03:50:45 +00001920 cFYI(1, "In CIFSSMBClose");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001921
1922/* do not retry on dead session on close */
1923 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00001924 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925 return 0;
1926 if (rc)
1927 return rc;
1928
Linus Torvalds1da177e2005-04-16 15:20:36 -07001929 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e2006-10-02 05:53:29 +00001930 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00001932 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001933 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001934 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00001935 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936 /* EINTR is expected when user ctl-c to kill app */
Joe Perchesb6b38f72010-04-21 03:50:45 +00001937 cERROR(1, "Send error in Close = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938 }
1939 }
1940
Linus Torvalds1da177e2005-04-16 15:20:36 -07001941 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00001942 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943 rc = 0;
1944
1945 return rc;
1946}
1947
1948int
Steve Frenchb298f222009-02-21 21:17:43 +00001949CIFSSMBFlush(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1950{
1951 int rc = 0;
1952 FLUSH_REQ *pSMB = NULL;
Joe Perchesb6b38f72010-04-21 03:50:45 +00001953 cFYI(1, "In CIFSSMBFlush");
Steve Frenchb298f222009-02-21 21:17:43 +00001954
1955 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
1956 if (rc)
1957 return rc;
1958
1959 pSMB->FileID = (__u16) smb_file_id;
1960 pSMB->ByteCount = 0;
1961 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
1962 cifs_stats_inc(&tcon->num_flushes);
1963 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001964 cERROR(1, "Send error in Flush = %d", rc);
Steve Frenchb298f222009-02-21 21:17:43 +00001965
1966 return rc;
1967}
1968
1969int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1971 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001972 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001973{
1974 int rc = 0;
1975 RENAME_REQ *pSMB = NULL;
1976 RENAME_RSP *pSMBr = NULL;
1977 int bytes_returned;
1978 int name_len, name_len2;
1979 __u16 count;
1980
Joe Perchesb6b38f72010-04-21 03:50:45 +00001981 cFYI(1, "In CIFSSMBRename");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982renameRetry:
1983 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1984 (void **) &pSMBr);
1985 if (rc)
1986 return rc;
1987
1988 pSMB->BufferFormat = 0x04;
1989 pSMB->SearchAttributes =
1990 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1991 ATTR_DIRECTORY);
1992
1993 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1994 name_len =
Steve French50c2f752007-07-13 00:33:32 +00001995 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001996 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997 name_len++; /* trailing null */
1998 name_len *= 2;
1999 pSMB->OldFileName[name_len] = 0x04; /* pad */
2000 /* protocol requires ASCII signature byte on Unicode string */
2001 pSMB->OldFileName[name_len + 1] = 0x00;
2002 name_len2 =
Steve French582d21e2008-05-13 04:54:12 +00002003 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002004 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2006 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002007 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002008 name_len = strnlen(fromName, PATH_MAX);
2009 name_len++; /* trailing null */
2010 strncpy(pSMB->OldFileName, fromName, name_len);
2011 name_len2 = strnlen(toName, PATH_MAX);
2012 name_len2++; /* trailing null */
2013 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2014 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2015 name_len2++; /* trailing null */
2016 name_len2++; /* signature byte */
2017 }
2018
2019 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002020 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002021 pSMB->ByteCount = cpu_to_le16(count);
2022
2023 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2024 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002025 cifs_stats_inc(&tcon->num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002026 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002027 cFYI(1, "Send error in rename = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002028
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029 cifs_buf_release(pSMB);
2030
2031 if (rc == -EAGAIN)
2032 goto renameRetry;
2033
2034 return rc;
2035}
2036
Steve French50c2f752007-07-13 00:33:32 +00002037int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002038 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002039 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002040{
2041 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2042 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002043 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002044 char *data_offset;
2045 char dummy_string[30];
2046 int rc = 0;
2047 int bytes_returned = 0;
2048 int len_of_str;
2049 __u16 params, param_offset, offset, count, byte_count;
2050
Joe Perchesb6b38f72010-04-21 03:50:45 +00002051 cFYI(1, "Rename to File by handle");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002052 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2053 (void **) &pSMBr);
2054 if (rc)
2055 return rc;
2056
2057 params = 6;
2058 pSMB->MaxSetupCount = 0;
2059 pSMB->Reserved = 0;
2060 pSMB->Flags = 0;
2061 pSMB->Timeout = 0;
2062 pSMB->Reserved2 = 0;
2063 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2064 offset = param_offset + params;
2065
2066 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2067 rename_info = (struct set_file_rename *) data_offset;
2068 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002069 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002070 pSMB->SetupCount = 1;
2071 pSMB->Reserved3 = 0;
2072 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2073 byte_count = 3 /* pad */ + params;
2074 pSMB->ParameterCount = cpu_to_le16(params);
2075 pSMB->TotalParameterCount = pSMB->ParameterCount;
2076 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2077 pSMB->DataOffset = cpu_to_le16(offset);
2078 /* construct random name ".cifs_tmp<inodenum><mid>" */
2079 rename_info->overwrite = cpu_to_le32(1);
2080 rename_info->root_fid = 0;
2081 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002082 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002083 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
2084 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002085 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002086 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05002087 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002088 target_name, PATH_MAX, nls_codepage,
2089 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002090 }
2091 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002092 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002093 byte_count += count;
2094 pSMB->DataCount = cpu_to_le16(count);
2095 pSMB->TotalDataCount = pSMB->DataCount;
2096 pSMB->Fid = netfid;
2097 pSMB->InformationLevel =
2098 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2099 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002100 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101 pSMB->ByteCount = cpu_to_le16(byte_count);
2102 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002103 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002104 cifs_stats_inc(&pTcon->num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002105 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002106 cFYI(1, "Send error in Rename (by file handle) = %d", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07002107
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108 cifs_buf_release(pSMB);
2109
2110 /* Note: On -EAGAIN error only caller can retry on handle based calls
2111 since file handle passed in no longer valid */
2112
2113 return rc;
2114}
2115
2116int
Steve French50c2f752007-07-13 00:33:32 +00002117CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName,
2118 const __u16 target_tid, const char *toName, const int flags,
2119 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002120{
2121 int rc = 0;
2122 COPY_REQ *pSMB = NULL;
2123 COPY_RSP *pSMBr = NULL;
2124 int bytes_returned;
2125 int name_len, name_len2;
2126 __u16 count;
2127
Joe Perchesb6b38f72010-04-21 03:50:45 +00002128 cFYI(1, "In CIFSSMBCopy");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002129copyRetry:
2130 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2131 (void **) &pSMBr);
2132 if (rc)
2133 return rc;
2134
2135 pSMB->BufferFormat = 0x04;
2136 pSMB->Tid2 = target_tid;
2137
2138 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2139
2140 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00002141 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07002142 fromName, PATH_MAX, nls_codepage,
2143 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002144 name_len++; /* trailing null */
2145 name_len *= 2;
2146 pSMB->OldFileName[name_len] = 0x04; /* pad */
2147 /* protocol requires ASCII signature byte on Unicode string */
2148 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002149 name_len2 =
2150 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002151 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002152 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2153 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002154 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002155 name_len = strnlen(fromName, PATH_MAX);
2156 name_len++; /* trailing null */
2157 strncpy(pSMB->OldFileName, fromName, name_len);
2158 name_len2 = strnlen(toName, PATH_MAX);
2159 name_len2++; /* trailing null */
2160 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2161 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2162 name_len2++; /* trailing null */
2163 name_len2++; /* signature byte */
2164 }
2165
2166 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002167 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002168 pSMB->ByteCount = cpu_to_le16(count);
2169
2170 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2171 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2172 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002173 cFYI(1, "Send error in copy = %d with %d files copied",
2174 rc, le16_to_cpu(pSMBr->CopyCount));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175 }
Steve French0d817bc2008-05-22 02:02:03 +00002176 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002177
2178 if (rc == -EAGAIN)
2179 goto copyRetry;
2180
2181 return rc;
2182}
2183
2184int
2185CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
2186 const char *fromName, const char *toName,
2187 const struct nls_table *nls_codepage)
2188{
2189 TRANSACTION2_SPI_REQ *pSMB = NULL;
2190 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2191 char *data_offset;
2192 int name_len;
2193 int name_len_target;
2194 int rc = 0;
2195 int bytes_returned = 0;
2196 __u16 params, param_offset, offset, byte_count;
2197
Joe Perchesb6b38f72010-04-21 03:50:45 +00002198 cFYI(1, "In Symlink Unix style");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002199createSymLinkRetry:
2200 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2201 (void **) &pSMBr);
2202 if (rc)
2203 return rc;
2204
2205 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2206 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002207 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002208 /* find define for this maxpathcomponent */
2209 , nls_codepage);
2210 name_len++; /* trailing null */
2211 name_len *= 2;
2212
Steve French50c2f752007-07-13 00:33:32 +00002213 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002214 name_len = strnlen(fromName, PATH_MAX);
2215 name_len++; /* trailing null */
2216 strncpy(pSMB->FileName, fromName, name_len);
2217 }
2218 params = 6 + name_len;
2219 pSMB->MaxSetupCount = 0;
2220 pSMB->Reserved = 0;
2221 pSMB->Flags = 0;
2222 pSMB->Timeout = 0;
2223 pSMB->Reserved2 = 0;
2224 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002225 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002226 offset = param_offset + params;
2227
2228 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2229 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2230 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08002231 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232 /* find define for this maxpathcomponent */
2233 , nls_codepage);
2234 name_len_target++; /* trailing null */
2235 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002236 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002237 name_len_target = strnlen(toName, PATH_MAX);
2238 name_len_target++; /* trailing null */
2239 strncpy(data_offset, toName, name_len_target);
2240 }
2241
2242 pSMB->MaxParameterCount = cpu_to_le16(2);
2243 /* BB find exact max on data count below from sess */
2244 pSMB->MaxDataCount = cpu_to_le16(1000);
2245 pSMB->SetupCount = 1;
2246 pSMB->Reserved3 = 0;
2247 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2248 byte_count = 3 /* pad */ + params + name_len_target;
2249 pSMB->DataCount = cpu_to_le16(name_len_target);
2250 pSMB->ParameterCount = cpu_to_le16(params);
2251 pSMB->TotalDataCount = pSMB->DataCount;
2252 pSMB->TotalParameterCount = pSMB->ParameterCount;
2253 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2254 pSMB->DataOffset = cpu_to_le16(offset);
2255 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2256 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002257 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002258 pSMB->ByteCount = cpu_to_le16(byte_count);
2259 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2260 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002261 cifs_stats_inc(&tcon->num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002262 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002263 cFYI(1, "Send error in SetPathInfo create symlink = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002264
Steve French0d817bc2008-05-22 02:02:03 +00002265 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002266
2267 if (rc == -EAGAIN)
2268 goto createSymLinkRetry;
2269
2270 return rc;
2271}
2272
2273int
2274CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2275 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002276 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002277{
2278 TRANSACTION2_SPI_REQ *pSMB = NULL;
2279 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2280 char *data_offset;
2281 int name_len;
2282 int name_len_target;
2283 int rc = 0;
2284 int bytes_returned = 0;
2285 __u16 params, param_offset, offset, byte_count;
2286
Joe Perchesb6b38f72010-04-21 03:50:45 +00002287 cFYI(1, "In Create Hard link Unix style");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002288createHardLinkRetry:
2289 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2290 (void **) &pSMBr);
2291 if (rc)
2292 return rc;
2293
2294 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05002295 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07002296 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002297 name_len++; /* trailing null */
2298 name_len *= 2;
2299
Steve French50c2f752007-07-13 00:33:32 +00002300 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002301 name_len = strnlen(toName, PATH_MAX);
2302 name_len++; /* trailing null */
2303 strncpy(pSMB->FileName, toName, name_len);
2304 }
2305 params = 6 + name_len;
2306 pSMB->MaxSetupCount = 0;
2307 pSMB->Reserved = 0;
2308 pSMB->Flags = 0;
2309 pSMB->Timeout = 0;
2310 pSMB->Reserved2 = 0;
2311 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002312 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002313 offset = param_offset + params;
2314
2315 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2316 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2317 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05002318 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07002319 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002320 name_len_target++; /* trailing null */
2321 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002322 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323 name_len_target = strnlen(fromName, PATH_MAX);
2324 name_len_target++; /* trailing null */
2325 strncpy(data_offset, fromName, name_len_target);
2326 }
2327
2328 pSMB->MaxParameterCount = cpu_to_le16(2);
2329 /* BB find exact max on data count below from sess*/
2330 pSMB->MaxDataCount = cpu_to_le16(1000);
2331 pSMB->SetupCount = 1;
2332 pSMB->Reserved3 = 0;
2333 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2334 byte_count = 3 /* pad */ + params + name_len_target;
2335 pSMB->ParameterCount = cpu_to_le16(params);
2336 pSMB->TotalParameterCount = pSMB->ParameterCount;
2337 pSMB->DataCount = cpu_to_le16(name_len_target);
2338 pSMB->TotalDataCount = pSMB->DataCount;
2339 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2340 pSMB->DataOffset = cpu_to_le16(offset);
2341 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2342 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002343 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002344 pSMB->ByteCount = cpu_to_le16(byte_count);
2345 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2346 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002347 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002348 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002349 cFYI(1, "Send error in SetPathInfo (hard link) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002350
2351 cifs_buf_release(pSMB);
2352 if (rc == -EAGAIN)
2353 goto createHardLinkRetry;
2354
2355 return rc;
2356}
2357
2358int
2359CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2360 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002361 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002362{
2363 int rc = 0;
2364 NT_RENAME_REQ *pSMB = NULL;
2365 RENAME_RSP *pSMBr = NULL;
2366 int bytes_returned;
2367 int name_len, name_len2;
2368 __u16 count;
2369
Joe Perchesb6b38f72010-04-21 03:50:45 +00002370 cFYI(1, "In CIFSCreateHardLink");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002371winCreateHardLinkRetry:
2372
2373 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2374 (void **) &pSMBr);
2375 if (rc)
2376 return rc;
2377
2378 pSMB->SearchAttributes =
2379 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2380 ATTR_DIRECTORY);
2381 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2382 pSMB->ClusterCount = 0;
2383
2384 pSMB->BufferFormat = 0x04;
2385
2386 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2387 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002388 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002389 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002390 name_len++; /* trailing null */
2391 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05002392
2393 /* protocol specifies ASCII buffer format (0x04) for unicode */
2394 pSMB->OldFileName[name_len] = 0x04;
2395 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002396 name_len2 =
Steve French50c2f752007-07-13 00:33:32 +00002397 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002398 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002399 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2400 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002401 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002402 name_len = strnlen(fromName, PATH_MAX);
2403 name_len++; /* trailing null */
2404 strncpy(pSMB->OldFileName, fromName, name_len);
2405 name_len2 = strnlen(toName, PATH_MAX);
2406 name_len2++; /* trailing null */
2407 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2408 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2409 name_len2++; /* trailing null */
2410 name_len2++; /* signature byte */
2411 }
2412
2413 count = 1 /* string type byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002414 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002415 pSMB->ByteCount = cpu_to_le16(count);
2416
2417 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2418 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002419 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002420 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002421 cFYI(1, "Send error in hard link (NT rename) = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00002422
Linus Torvalds1da177e2005-04-16 15:20:36 -07002423 cifs_buf_release(pSMB);
2424 if (rc == -EAGAIN)
2425 goto winCreateHardLinkRetry;
2426
2427 return rc;
2428}
2429
2430int
2431CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04002432 const unsigned char *searchName, char **symlinkinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002433 const struct nls_table *nls_codepage)
2434{
2435/* SMB_QUERY_FILE_UNIX_LINK */
2436 TRANSACTION2_QPI_REQ *pSMB = NULL;
2437 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2438 int rc = 0;
2439 int bytes_returned;
2440 int name_len;
2441 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04002442 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002443
Joe Perchesb6b38f72010-04-21 03:50:45 +00002444 cFYI(1, "In QPathSymLinkInfo (Unix) for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002445
2446querySymLinkRetry:
2447 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2448 (void **) &pSMBr);
2449 if (rc)
2450 return rc;
2451
2452 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2453 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002454 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
2455 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002456 name_len++; /* trailing null */
2457 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002458 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002459 name_len = strnlen(searchName, PATH_MAX);
2460 name_len++; /* trailing null */
2461 strncpy(pSMB->FileName, searchName, name_len);
2462 }
2463
2464 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2465 pSMB->TotalDataCount = 0;
2466 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04002467 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002468 pSMB->MaxSetupCount = 0;
2469 pSMB->Reserved = 0;
2470 pSMB->Flags = 0;
2471 pSMB->Timeout = 0;
2472 pSMB->Reserved2 = 0;
2473 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00002474 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002475 pSMB->DataCount = 0;
2476 pSMB->DataOffset = 0;
2477 pSMB->SetupCount = 1;
2478 pSMB->Reserved3 = 0;
2479 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2480 byte_count = params + 1 /* pad */ ;
2481 pSMB->TotalParameterCount = cpu_to_le16(params);
2482 pSMB->ParameterCount = pSMB->TotalParameterCount;
2483 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2484 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002485 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002486 pSMB->ByteCount = cpu_to_le16(byte_count);
2487
2488 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2489 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2490 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002491 cFYI(1, "Send error in QuerySymLinkInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002492 } else {
2493 /* decode response */
2494
2495 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002496 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04002497 if (rc || get_bcc(&pSMBr->hdr) < 2)
Jeff Layton460b9692009-04-30 07:17:56 -04002498 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002499 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00002500 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04002501 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002502
Jeff Layton460b9692009-04-30 07:17:56 -04002503 data_start = ((char *) &pSMBr->hdr.Protocol) +
2504 le16_to_cpu(pSMBr->t2.DataOffset);
2505
Steve French0e0d2cf2009-05-01 05:27:32 +00002506 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2507 is_unicode = true;
2508 else
2509 is_unicode = false;
2510
Steve French737b7582005-04-28 22:41:06 -07002511 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchd185cda2009-04-30 17:45:10 +00002512 *symlinkinfo = cifs_strndup_from_ucs(data_start, count,
Steve French0e0d2cf2009-05-01 05:27:32 +00002513 is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04002514 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04002515 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002516 }
2517 }
2518 cifs_buf_release(pSMB);
2519 if (rc == -EAGAIN)
2520 goto querySymLinkRetry;
2521 return rc;
2522}
2523
Steve Frenchc52a9552011-02-24 06:16:22 +00002524#ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL
2525/*
2526 * Recent Windows versions now create symlinks more frequently
2527 * and they use the "reparse point" mechanism below. We can of course
2528 * do symlinks nicely to Samba and other servers which support the
2529 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
2530 * "MF" symlinks optionally, but for recent Windows we really need to
2531 * reenable the code below and fix the cifs_symlink callers to handle this.
2532 * In the interim this code has been moved to its own config option so
2533 * it is not compiled in by default until callers fixed up and more tested.
2534 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002535int
2536CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2537 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00002538 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002539 const struct nls_table *nls_codepage)
2540{
2541 int rc = 0;
2542 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00002543 struct smb_com_transaction_ioctl_req *pSMB;
2544 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002545
Joe Perchesb6b38f72010-04-21 03:50:45 +00002546 cFYI(1, "In Windows reparse style QueryLink for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002547 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2548 (void **) &pSMBr);
2549 if (rc)
2550 return rc;
2551
2552 pSMB->TotalParameterCount = 0 ;
2553 pSMB->TotalDataCount = 0;
2554 pSMB->MaxParameterCount = cpu_to_le32(2);
2555 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002556 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2557 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002558 pSMB->MaxSetupCount = 4;
2559 pSMB->Reserved = 0;
2560 pSMB->ParameterOffset = 0;
2561 pSMB->DataCount = 0;
2562 pSMB->DataOffset = 0;
2563 pSMB->SetupCount = 4;
2564 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2565 pSMB->ParameterCount = pSMB->TotalParameterCount;
2566 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2567 pSMB->IsFsctl = 1; /* FSCTL */
2568 pSMB->IsRootFlag = 0;
2569 pSMB->Fid = fid; /* file handle always le */
2570 pSMB->ByteCount = 0;
2571
2572 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2573 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2574 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002575 cFYI(1, "Send error in QueryReparseLinkInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002576 } else { /* decode response */
2577 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2578 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
Jeff Layton820a8032011-05-04 08:05:26 -04002579 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
2580 /* BB also check enough total bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002581 rc = -EIO; /* bad smb */
Steve Frenchafe48c32009-05-02 05:25:46 +00002582 goto qreparse_out;
2583 }
2584 if (data_count && (data_count < 2048)) {
2585 char *end_of_smb = 2 /* sizeof byte count */ +
Jeff Layton820a8032011-05-04 08:05:26 -04002586 get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002587
Steve Frenchafe48c32009-05-02 05:25:46 +00002588 struct reparse_data *reparse_buf =
Steve French50c2f752007-07-13 00:33:32 +00002589 (struct reparse_data *)
2590 ((char *)&pSMBr->hdr.Protocol
2591 + data_offset);
Steve Frenchafe48c32009-05-02 05:25:46 +00002592 if ((char *)reparse_buf >= end_of_smb) {
2593 rc = -EIO;
2594 goto qreparse_out;
2595 }
2596 if ((reparse_buf->LinkNamesBuf +
2597 reparse_buf->TargetNameOffset +
2598 reparse_buf->TargetNameLen) > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002599 cFYI(1, "reparse buf beyond SMB");
Steve Frenchafe48c32009-05-02 05:25:46 +00002600 rc = -EIO;
2601 goto qreparse_out;
2602 }
Steve French50c2f752007-07-13 00:33:32 +00002603
Steve Frenchafe48c32009-05-02 05:25:46 +00002604 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2605 cifs_from_ucs2(symlinkinfo, (__le16 *)
Steve French50c2f752007-07-13 00:33:32 +00002606 (reparse_buf->LinkNamesBuf +
2607 reparse_buf->TargetNameOffset),
Steve Frenchafe48c32009-05-02 05:25:46 +00002608 buflen,
2609 reparse_buf->TargetNameLen,
2610 nls_codepage, 0);
2611 } else { /* ASCII names */
2612 strncpy(symlinkinfo,
2613 reparse_buf->LinkNamesBuf +
2614 reparse_buf->TargetNameOffset,
2615 min_t(const int, buflen,
2616 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002617 }
Steve Frenchafe48c32009-05-02 05:25:46 +00002618 } else {
2619 rc = -EIO;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002620 cFYI(1, "Invalid return data count on "
2621 "get reparse info ioctl");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002622 }
Steve Frenchafe48c32009-05-02 05:25:46 +00002623 symlinkinfo[buflen] = 0; /* just in case so the caller
2624 does not go off the end of the buffer */
Joe Perchesb6b38f72010-04-21 03:50:45 +00002625 cFYI(1, "readlink result - %s", symlinkinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002626 }
Steve French989c7e52009-05-02 05:32:20 +00002627
Linus Torvalds1da177e2005-04-16 15:20:36 -07002628qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002629 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002630
2631 /* Note: On -EAGAIN error only caller can retry on handle based calls
2632 since file handle passed in no longer valid */
2633
2634 return rc;
2635}
Steve Frenchc52a9552011-02-24 06:16:22 +00002636#endif /* CIFS_SYMLINK_EXPERIMENTAL */ /* BB temporarily unused */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002637
2638#ifdef CONFIG_CIFS_POSIX
2639
2640/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00002641static void cifs_convert_ace(posix_acl_xattr_entry *ace,
2642 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002643{
2644 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002645 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2646 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2647 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesb6b38f72010-04-21 03:50:45 +00002648 /* cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002649
2650 return;
2651}
2652
2653/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00002654static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
2655 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656{
2657 int size = 0;
2658 int i;
2659 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00002660 struct cifs_posix_ace *pACE;
2661 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
2662 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002663
2664 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2665 return -EOPNOTSUPP;
2666
Steve French790fe572007-07-07 19:25:05 +00002667 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002668 count = le16_to_cpu(cifs_acl->access_entry_count);
2669 pACE = &cifs_acl->ace_array[0];
2670 size = sizeof(struct cifs_posix_acl);
2671 size += sizeof(struct cifs_posix_ace) * count;
2672 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002673 if (size_of_data_area < size) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002674 cFYI(1, "bad CIFS POSIX ACL size %d vs. %d",
2675 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002676 return -EINVAL;
2677 }
Steve French790fe572007-07-07 19:25:05 +00002678 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002679 count = le16_to_cpu(cifs_acl->access_entry_count);
2680 size = sizeof(struct cifs_posix_acl);
2681 size += sizeof(struct cifs_posix_ace) * count;
2682/* skip past access ACEs to get to default ACEs */
2683 pACE = &cifs_acl->ace_array[count];
2684 count = le16_to_cpu(cifs_acl->default_entry_count);
2685 size += sizeof(struct cifs_posix_ace) * count;
2686 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002687 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002688 return -EINVAL;
2689 } else {
2690 /* illegal type */
2691 return -EINVAL;
2692 }
2693
2694 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00002695 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00002696 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00002697 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002698 return -ERANGE;
2699 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002700 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00002701 for (i = 0; i < count ; i++) {
2702 cifs_convert_ace(&local_acl->a_entries[i], pACE);
2703 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704 }
2705 }
2706 return size;
2707}
2708
Steve French50c2f752007-07-13 00:33:32 +00002709static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
2710 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002711{
2712 __u16 rc = 0; /* 0 = ACL converted ok */
2713
Steve Frenchff7feac2005-11-15 16:45:16 -08002714 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2715 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002716 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00002717 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002718 /* Probably no need to le convert -1 on any arch but can not hurt */
2719 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00002720 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002721 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesb6b38f72010-04-21 03:50:45 +00002722 /*cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id);*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002723 return rc;
2724}
2725
2726/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00002727static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
2728 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002729{
2730 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00002731 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
2732 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002733 int count;
2734 int i;
2735
Steve French790fe572007-07-07 19:25:05 +00002736 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002737 return 0;
2738
2739 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesb6b38f72010-04-21 03:50:45 +00002740 cFYI(1, "setting acl with %d entries from buf of length %d and "
Steve French63135e02007-07-17 17:34:02 +00002741 "version of %d",
Joe Perchesb6b38f72010-04-21 03:50:45 +00002742 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00002743 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002744 cFYI(1, "unknown POSIX ACL version %d",
2745 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002746 return 0;
2747 }
2748 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00002749 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08002750 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00002751 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08002752 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002753 else {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002754 cFYI(1, "unknown ACL type %d", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002755 return 0;
2756 }
Steve French50c2f752007-07-13 00:33:32 +00002757 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002758 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2759 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00002760 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002761 /* ACE not converted */
2762 break;
2763 }
2764 }
Steve French790fe572007-07-07 19:25:05 +00002765 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002766 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2767 rc += sizeof(struct cifs_posix_acl);
2768 /* BB add check to make sure ACL does not overflow SMB */
2769 }
2770 return rc;
2771}
2772
2773int
2774CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002775 const unsigned char *searchName,
2776 char *acl_inf, const int buflen, const int acl_type,
2777 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002778{
2779/* SMB_QUERY_POSIX_ACL */
2780 TRANSACTION2_QPI_REQ *pSMB = NULL;
2781 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2782 int rc = 0;
2783 int bytes_returned;
2784 int name_len;
2785 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00002786
Joe Perchesb6b38f72010-04-21 03:50:45 +00002787 cFYI(1, "In GetPosixACL (Unix) for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002788
2789queryAclRetry:
2790 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2791 (void **) &pSMBr);
2792 if (rc)
2793 return rc;
Steve French50c2f752007-07-13 00:33:32 +00002794
Linus Torvalds1da177e2005-04-16 15:20:36 -07002795 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2796 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002797 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002798 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002799 name_len++; /* trailing null */
2800 name_len *= 2;
2801 pSMB->FileName[name_len] = 0;
2802 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00002803 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002804 name_len = strnlen(searchName, PATH_MAX);
2805 name_len++; /* trailing null */
2806 strncpy(pSMB->FileName, searchName, name_len);
2807 }
2808
2809 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2810 pSMB->TotalDataCount = 0;
2811 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00002812 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002813 pSMB->MaxDataCount = cpu_to_le16(4000);
2814 pSMB->MaxSetupCount = 0;
2815 pSMB->Reserved = 0;
2816 pSMB->Flags = 0;
2817 pSMB->Timeout = 0;
2818 pSMB->Reserved2 = 0;
2819 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00002820 offsetof(struct smb_com_transaction2_qpi_req,
2821 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002822 pSMB->DataCount = 0;
2823 pSMB->DataOffset = 0;
2824 pSMB->SetupCount = 1;
2825 pSMB->Reserved3 = 0;
2826 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2827 byte_count = params + 1 /* pad */ ;
2828 pSMB->TotalParameterCount = cpu_to_le16(params);
2829 pSMB->ParameterCount = pSMB->TotalParameterCount;
2830 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2831 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002832 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002833 pSMB->ByteCount = cpu_to_le16(byte_count);
2834
2835 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2836 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08002837 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002838 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002839 cFYI(1, "Send error in Query POSIX ACL = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002840 } else {
2841 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00002842
Linus Torvalds1da177e2005-04-16 15:20:36 -07002843 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002844 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04002845 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002846 rc = -EIO; /* bad smb */
2847 else {
2848 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2849 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2850 rc = cifs_copy_posix_acl(acl_inf,
2851 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00002852 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002853 }
2854 }
2855 cifs_buf_release(pSMB);
2856 if (rc == -EAGAIN)
2857 goto queryAclRetry;
2858 return rc;
2859}
2860
2861int
2862CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002863 const unsigned char *fileName,
2864 const char *local_acl, const int buflen,
2865 const int acl_type,
2866 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002867{
2868 struct smb_com_transaction2_spi_req *pSMB = NULL;
2869 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2870 char *parm_data;
2871 int name_len;
2872 int rc = 0;
2873 int bytes_returned = 0;
2874 __u16 params, byte_count, data_count, param_offset, offset;
2875
Joe Perchesb6b38f72010-04-21 03:50:45 +00002876 cFYI(1, "In SetPosixACL (Unix) for path %s", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002877setAclRetry:
2878 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002879 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002880 if (rc)
2881 return rc;
2882 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2883 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002884 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002885 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002886 name_len++; /* trailing null */
2887 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002888 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002889 name_len = strnlen(fileName, PATH_MAX);
2890 name_len++; /* trailing null */
2891 strncpy(pSMB->FileName, fileName, name_len);
2892 }
2893 params = 6 + name_len;
2894 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00002895 /* BB find max SMB size from sess */
2896 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002897 pSMB->MaxSetupCount = 0;
2898 pSMB->Reserved = 0;
2899 pSMB->Flags = 0;
2900 pSMB->Timeout = 0;
2901 pSMB->Reserved2 = 0;
2902 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002903 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002904 offset = param_offset + params;
2905 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2906 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2907
2908 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00002909 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002910
Steve French790fe572007-07-07 19:25:05 +00002911 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002912 rc = -EOPNOTSUPP;
2913 goto setACLerrorExit;
2914 }
2915 pSMB->DataOffset = cpu_to_le16(offset);
2916 pSMB->SetupCount = 1;
2917 pSMB->Reserved3 = 0;
2918 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2919 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2920 byte_count = 3 /* pad */ + params + data_count;
2921 pSMB->DataCount = cpu_to_le16(data_count);
2922 pSMB->TotalDataCount = pSMB->DataCount;
2923 pSMB->ParameterCount = cpu_to_le16(params);
2924 pSMB->TotalParameterCount = pSMB->ParameterCount;
2925 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002926 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002927 pSMB->ByteCount = cpu_to_le16(byte_count);
2928 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002929 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00002930 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002931 cFYI(1, "Set POSIX ACL returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002932
2933setACLerrorExit:
2934 cifs_buf_release(pSMB);
2935 if (rc == -EAGAIN)
2936 goto setAclRetry;
2937 return rc;
2938}
2939
Steve Frenchf654bac2005-04-28 22:41:04 -07002940/* BB fix tabs in this function FIXME BB */
2941int
2942CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00002943 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07002944{
Steve French50c2f752007-07-13 00:33:32 +00002945 int rc = 0;
2946 struct smb_t2_qfi_req *pSMB = NULL;
2947 struct smb_t2_qfi_rsp *pSMBr = NULL;
2948 int bytes_returned;
2949 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07002950
Joe Perchesb6b38f72010-04-21 03:50:45 +00002951 cFYI(1, "In GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00002952 if (tcon == NULL)
2953 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07002954
2955GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00002956 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2957 (void **) &pSMBr);
2958 if (rc)
2959 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07002960
Steve Frenchad7a2922008-02-07 23:25:02 +00002961 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00002962 pSMB->t2.TotalDataCount = 0;
2963 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
2964 /* BB find exact max data count below from sess structure BB */
2965 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2966 pSMB->t2.MaxSetupCount = 0;
2967 pSMB->t2.Reserved = 0;
2968 pSMB->t2.Flags = 0;
2969 pSMB->t2.Timeout = 0;
2970 pSMB->t2.Reserved2 = 0;
2971 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2972 Fid) - 4);
2973 pSMB->t2.DataCount = 0;
2974 pSMB->t2.DataOffset = 0;
2975 pSMB->t2.SetupCount = 1;
2976 pSMB->t2.Reserved3 = 0;
2977 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2978 byte_count = params + 1 /* pad */ ;
2979 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2980 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2981 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
2982 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07002983 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002984 inc_rfc1001_len(pSMB, byte_count);
Steve French790fe572007-07-07 19:25:05 +00002985 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07002986
Steve French790fe572007-07-07 19:25:05 +00002987 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2988 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2989 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002990 cFYI(1, "error %d in GetExtAttr", rc);
Steve French790fe572007-07-07 19:25:05 +00002991 } else {
2992 /* decode response */
2993 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00002994 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04002995 if (rc || get_bcc(&pSMBr->hdr) < 2)
Steve French790fe572007-07-07 19:25:05 +00002996 /* If rc should we check for EOPNOSUPP and
2997 disable the srvino flag? or in caller? */
2998 rc = -EIO; /* bad smb */
2999 else {
3000 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3001 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3002 struct file_chattr_info *pfinfo;
3003 /* BB Do we need a cast or hash here ? */
3004 if (count != 16) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003005 cFYI(1, "Illegal size ret in GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00003006 rc = -EIO;
3007 goto GetExtAttrOut;
3008 }
3009 pfinfo = (struct file_chattr_info *)
3010 (data_offset + (char *) &pSMBr->hdr.Protocol);
3011 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003012 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003013 }
3014 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003015GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003016 cifs_buf_release(pSMB);
3017 if (rc == -EAGAIN)
3018 goto GetExtAttrRetry;
3019 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003020}
3021
Steve Frenchf654bac2005-04-28 22:41:04 -07003022#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003023
Jeff Layton79df1ba2010-12-06 12:52:08 -05003024#ifdef CONFIG_CIFS_ACL
3025/*
3026 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3027 * all NT TRANSACTS that we init here have total parm and data under about 400
3028 * bytes (to fit in small cifs buffer size), which is the case so far, it
3029 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3030 * returned setup area) and MaxParameterCount (returned parms size) must be set
3031 * by caller
3032 */
3033static int
3034smb_init_nttransact(const __u16 sub_command, const int setup_count,
3035 const int parm_len, struct cifsTconInfo *tcon,
3036 void **ret_buf)
3037{
3038 int rc;
3039 __u32 temp_offset;
3040 struct smb_com_ntransact_req *pSMB;
3041
3042 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3043 (void **)&pSMB);
3044 if (rc)
3045 return rc;
3046 *ret_buf = (void *)pSMB;
3047 pSMB->Reserved = 0;
3048 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3049 pSMB->TotalDataCount = 0;
3050 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
3051 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3052 pSMB->ParameterCount = pSMB->TotalParameterCount;
3053 pSMB->DataCount = pSMB->TotalDataCount;
3054 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3055 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3056 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3057 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3058 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3059 pSMB->SubCommand = cpu_to_le16(sub_command);
3060 return 0;
3061}
3062
3063static int
3064validate_ntransact(char *buf, char **ppparm, char **ppdata,
3065 __u32 *pparmlen, __u32 *pdatalen)
3066{
3067 char *end_of_smb;
3068 __u32 data_count, data_offset, parm_count, parm_offset;
3069 struct smb_com_ntransact_rsp *pSMBr;
Jeff Layton820a8032011-05-04 08:05:26 -04003070 u16 bcc;
Jeff Layton79df1ba2010-12-06 12:52:08 -05003071
3072 *pdatalen = 0;
3073 *pparmlen = 0;
3074
3075 if (buf == NULL)
3076 return -EINVAL;
3077
3078 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3079
Jeff Layton820a8032011-05-04 08:05:26 -04003080 bcc = get_bcc(&pSMBr->hdr);
3081 end_of_smb = 2 /* sizeof byte count */ + bcc +
Jeff Layton79df1ba2010-12-06 12:52:08 -05003082 (char *)&pSMBr->ByteCount;
3083
3084 data_offset = le32_to_cpu(pSMBr->DataOffset);
3085 data_count = le32_to_cpu(pSMBr->DataCount);
3086 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3087 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3088
3089 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3090 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3091
3092 /* should we also check that parm and data areas do not overlap? */
3093 if (*ppparm > end_of_smb) {
3094 cFYI(1, "parms start after end of smb");
3095 return -EINVAL;
3096 } else if (parm_count + *ppparm > end_of_smb) {
3097 cFYI(1, "parm end after end of smb");
3098 return -EINVAL;
3099 } else if (*ppdata > end_of_smb) {
3100 cFYI(1, "data starts after end of smb");
3101 return -EINVAL;
3102 } else if (data_count + *ppdata > end_of_smb) {
3103 cFYI(1, "data %p + count %d (%p) past smb end %p start %p",
3104 *ppdata, data_count, (data_count + *ppdata),
3105 end_of_smb, pSMBr);
3106 return -EINVAL;
Jeff Layton820a8032011-05-04 08:05:26 -04003107 } else if (parm_count + data_count > bcc) {
Jeff Layton79df1ba2010-12-06 12:52:08 -05003108 cFYI(1, "parm count and data count larger than SMB");
3109 return -EINVAL;
3110 }
3111 *pdatalen = data_count;
3112 *pparmlen = parm_count;
3113 return 0;
3114}
3115
Steve French0a4b92c2006-01-12 15:44:21 -08003116/* Get Security Descriptor (by handle) from remote server for a file or dir */
3117int
3118CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
Steve French630f3f02007-10-25 21:17:17 +00003119 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003120{
3121 int rc = 0;
3122 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003123 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003124 struct kvec iov[1];
3125
Joe Perchesb6b38f72010-04-21 03:50:45 +00003126 cFYI(1, "GetCifsACL");
Steve French0a4b92c2006-01-12 15:44:21 -08003127
Steve French630f3f02007-10-25 21:17:17 +00003128 *pbuflen = 0;
3129 *acl_inf = NULL;
3130
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003131 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003132 8 /* parm len */, tcon, (void **) &pSMB);
3133 if (rc)
3134 return rc;
3135
3136 pSMB->MaxParameterCount = cpu_to_le32(4);
3137 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3138 pSMB->MaxSetupCount = 0;
3139 pSMB->Fid = fid; /* file handle always le */
3140 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3141 CIFS_ACL_DACL);
3142 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003143 inc_rfc1001_len(pSMB, 11);
Steve French0a4b92c2006-01-12 15:44:21 -08003144 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003145 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French0a4b92c2006-01-12 15:44:21 -08003146
Steve Frencha761ac52007-10-18 21:45:27 +00003147 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Jeff Layton77499812011-01-11 07:24:23 -05003148 0);
Steve French0a4b92c2006-01-12 15:44:21 -08003149 cifs_stats_inc(&tcon->num_acl_get);
3150 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003151 cFYI(1, "Send error in QuerySecDesc = %d", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08003152 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003153 __le32 *parm;
Steve French630f3f02007-10-25 21:17:17 +00003154 __u32 parm_len;
3155 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003156 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f02007-10-25 21:17:17 +00003157 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003158
3159/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003160 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f02007-10-25 21:17:17 +00003161 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003162 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003163 goto qsec_out;
3164 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3165
Joe Perchesb6b38f72010-04-21 03:50:45 +00003166 cFYI(1, "smb %p parm %p data %p", pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08003167
3168 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3169 rc = -EIO; /* bad smb */
Steve French630f3f02007-10-25 21:17:17 +00003170 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003171 goto qsec_out;
3172 }
3173
3174/* BB check that data area is minimum length and as big as acl_len */
3175
Steve Frenchaf6f4612007-10-16 18:40:37 +00003176 acl_len = le32_to_cpu(*parm);
Steve French630f3f02007-10-25 21:17:17 +00003177 if (acl_len != *pbuflen) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003178 cERROR(1, "acl length %d does not match %d",
3179 acl_len, *pbuflen);
Steve French630f3f02007-10-25 21:17:17 +00003180 if (*pbuflen > acl_len)
3181 *pbuflen = acl_len;
3182 }
Steve French0a4b92c2006-01-12 15:44:21 -08003183
Steve French630f3f02007-10-25 21:17:17 +00003184 /* check if buffer is big enough for the acl
3185 header followed by the smallest SID */
3186 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3187 (*pbuflen >= 64 * 1024)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003188 cERROR(1, "bad acl length %d", *pbuflen);
Steve French630f3f02007-10-25 21:17:17 +00003189 rc = -EINVAL;
3190 *pbuflen = 0;
3191 } else {
3192 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3193 if (*acl_inf == NULL) {
3194 *pbuflen = 0;
3195 rc = -ENOMEM;
3196 }
3197 memcpy(*acl_inf, pdata, *pbuflen);
3198 }
Steve French0a4b92c2006-01-12 15:44:21 -08003199 }
3200qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003201 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003202 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003203 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003204 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003205/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003206 return rc;
3207}
Steve French97837582007-12-31 07:47:21 +00003208
3209int
3210CIFSSMBSetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3211 struct cifs_ntsd *pntsd, __u32 acllen)
3212{
3213 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3214 int rc = 0;
3215 int bytes_returned = 0;
3216 SET_SEC_DESC_REQ *pSMB = NULL;
3217 NTRANSACT_RSP *pSMBr = NULL;
3218
3219setCifsAclRetry:
3220 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB,
3221 (void **) &pSMBr);
3222 if (rc)
3223 return (rc);
3224
3225 pSMB->MaxSetupCount = 0;
3226 pSMB->Reserved = 0;
3227
3228 param_count = 8;
3229 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3230 data_count = acllen;
3231 data_offset = param_offset + param_count;
3232 byte_count = 3 /* pad */ + param_count;
3233
3234 pSMB->DataCount = cpu_to_le32(data_count);
3235 pSMB->TotalDataCount = pSMB->DataCount;
3236 pSMB->MaxParameterCount = cpu_to_le32(4);
3237 pSMB->MaxDataCount = cpu_to_le32(16384);
3238 pSMB->ParameterCount = cpu_to_le32(param_count);
3239 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3240 pSMB->TotalParameterCount = pSMB->ParameterCount;
3241 pSMB->DataOffset = cpu_to_le32(data_offset);
3242 pSMB->SetupCount = 0;
3243 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3244 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3245
3246 pSMB->Fid = fid; /* file handle always le */
3247 pSMB->Reserved2 = 0;
3248 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_DACL);
3249
3250 if (pntsd && acllen) {
3251 memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
3252 (char *) pntsd,
3253 acllen);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003254 inc_rfc1001_len(pSMB, byte_count + data_count);
Steve French97837582007-12-31 07:47:21 +00003255 } else
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003256 inc_rfc1001_len(pSMB, byte_count);
Steve French97837582007-12-31 07:47:21 +00003257
3258 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3259 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3260
Joe Perchesb6b38f72010-04-21 03:50:45 +00003261 cFYI(1, "SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00003262 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003263 cFYI(1, "Set CIFS ACL returned %d", rc);
Steve French97837582007-12-31 07:47:21 +00003264 cifs_buf_release(pSMB);
3265
3266 if (rc == -EAGAIN)
3267 goto setCifsAclRetry;
3268
3269 return (rc);
3270}
3271
Jeff Layton79df1ba2010-12-06 12:52:08 -05003272#endif /* CONFIG_CIFS_ACL */
Steve French0a4b92c2006-01-12 15:44:21 -08003273
Steve French6b8edfe2005-08-23 20:26:03 -07003274/* Legacy Query Path Information call for lookup to old servers such
3275 as Win9x/WinME */
3276int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003277 const unsigned char *searchName,
3278 FILE_ALL_INFO *pFinfo,
3279 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003280{
Steve Frenchad7a2922008-02-07 23:25:02 +00003281 QUERY_INFORMATION_REQ *pSMB;
3282 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003283 int rc = 0;
3284 int bytes_returned;
3285 int name_len;
3286
Joe Perchesb6b38f72010-04-21 03:50:45 +00003287 cFYI(1, "In SMBQPath path %s", searchName);
Steve French6b8edfe2005-08-23 20:26:03 -07003288QInfRetry:
3289 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003290 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003291 if (rc)
3292 return rc;
3293
3294 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3295 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003296 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3297 PATH_MAX, nls_codepage, remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003298 name_len++; /* trailing null */
3299 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003300 } else {
Steve French6b8edfe2005-08-23 20:26:03 -07003301 name_len = strnlen(searchName, PATH_MAX);
3302 name_len++; /* trailing null */
3303 strncpy(pSMB->FileName, searchName, name_len);
3304 }
3305 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003306 name_len++; /* account for buffer type byte */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003307 inc_rfc1001_len(pSMB, (__u16)name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07003308 pSMB->ByteCount = cpu_to_le16(name_len);
3309
3310 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003311 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003312 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003313 cFYI(1, "Send error in QueryInfo = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00003314 } else if (pFinfo) {
Steve French1bd5bbc2006-09-28 03:35:57 +00003315 struct timespec ts;
3316 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00003317
3318 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003319 /* BB FIXME - add time zone adjustment BB */
Steve French6b8edfe2005-08-23 20:26:03 -07003320 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003321 ts.tv_nsec = 0;
3322 ts.tv_sec = time;
3323 /* decode time fields */
Al Viro733f99a2006-10-14 16:48:26 +01003324 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
Steve French1bd5bbc2006-09-28 03:35:57 +00003325 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3326 pFinfo->LastAccessTime = 0;
Steve French70ca7342005-09-22 16:32:06 -07003327 pFinfo->AllocationSize =
3328 cpu_to_le64(le32_to_cpu(pSMBr->size));
3329 pFinfo->EndOfFile = pFinfo->AllocationSize;
3330 pFinfo->Attributes =
3331 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003332 } else
3333 rc = -EIO; /* bad buffer passed in */
3334
3335 cifs_buf_release(pSMB);
3336
3337 if (rc == -EAGAIN)
3338 goto QInfRetry;
3339
3340 return rc;
3341}
3342
Jeff Laytonbcd53572010-02-12 07:44:16 -05003343int
3344CIFSSMBQFileInfo(const int xid, struct cifsTconInfo *tcon,
3345 u16 netfid, FILE_ALL_INFO *pFindData)
3346{
3347 struct smb_t2_qfi_req *pSMB = NULL;
3348 struct smb_t2_qfi_rsp *pSMBr = NULL;
3349 int rc = 0;
3350 int bytes_returned;
3351 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07003352
Jeff Laytonbcd53572010-02-12 07:44:16 -05003353QFileInfoRetry:
3354 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3355 (void **) &pSMBr);
3356 if (rc)
3357 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07003358
Jeff Laytonbcd53572010-02-12 07:44:16 -05003359 params = 2 /* level */ + 2 /* fid */;
3360 pSMB->t2.TotalDataCount = 0;
3361 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3362 /* BB find exact max data count below from sess structure BB */
3363 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3364 pSMB->t2.MaxSetupCount = 0;
3365 pSMB->t2.Reserved = 0;
3366 pSMB->t2.Flags = 0;
3367 pSMB->t2.Timeout = 0;
3368 pSMB->t2.Reserved2 = 0;
3369 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3370 Fid) - 4);
3371 pSMB->t2.DataCount = 0;
3372 pSMB->t2.DataOffset = 0;
3373 pSMB->t2.SetupCount = 1;
3374 pSMB->t2.Reserved3 = 0;
3375 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3376 byte_count = params + 1 /* pad */ ;
3377 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3378 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3379 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3380 pSMB->Pad = 0;
3381 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003382 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003383
3384 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3385 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3386 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00003387 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003388 } else { /* decode response */
3389 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3390
3391 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3392 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04003393 else if (get_bcc(&pSMBr->hdr) < 40)
Jeff Laytonbcd53572010-02-12 07:44:16 -05003394 rc = -EIO; /* bad smb */
3395 else if (pFindData) {
3396 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3397 memcpy((char *) pFindData,
3398 (char *) &pSMBr->hdr.Protocol +
3399 data_offset, sizeof(FILE_ALL_INFO));
3400 } else
3401 rc = -ENOMEM;
3402 }
3403 cifs_buf_release(pSMB);
3404 if (rc == -EAGAIN)
3405 goto QFileInfoRetry;
3406
3407 return rc;
3408}
Steve French6b8edfe2005-08-23 20:26:03 -07003409
Linus Torvalds1da177e2005-04-16 15:20:36 -07003410int
3411CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3412 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003413 FILE_ALL_INFO *pFindData,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003414 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003415 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003416{
3417/* level 263 SMB_QUERY_FILE_ALL_INFO */
3418 TRANSACTION2_QPI_REQ *pSMB = NULL;
3419 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3420 int rc = 0;
3421 int bytes_returned;
3422 int name_len;
3423 __u16 params, byte_count;
3424
Joe Perchesb6b38f72010-04-21 03:50:45 +00003425/* cFYI(1, "In QPathInfo path %s", searchName); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003426QPathInfoRetry:
3427 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3428 (void **) &pSMBr);
3429 if (rc)
3430 return rc;
3431
3432 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3433 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003434 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003435 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003436 name_len++; /* trailing null */
3437 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003438 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003439 name_len = strnlen(searchName, PATH_MAX);
3440 name_len++; /* trailing null */
3441 strncpy(pSMB->FileName, searchName, name_len);
3442 }
3443
Steve French50c2f752007-07-13 00:33:32 +00003444 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003445 pSMB->TotalDataCount = 0;
3446 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003447 /* BB find exact max SMB PDU from sess structure BB */
3448 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003449 pSMB->MaxSetupCount = 0;
3450 pSMB->Reserved = 0;
3451 pSMB->Flags = 0;
3452 pSMB->Timeout = 0;
3453 pSMB->Reserved2 = 0;
3454 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003455 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003456 pSMB->DataCount = 0;
3457 pSMB->DataOffset = 0;
3458 pSMB->SetupCount = 1;
3459 pSMB->Reserved3 = 0;
3460 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3461 byte_count = params + 1 /* pad */ ;
3462 pSMB->TotalParameterCount = cpu_to_le16(params);
3463 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00003464 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003465 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3466 else
3467 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003468 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003469 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003470 pSMB->ByteCount = cpu_to_le16(byte_count);
3471
3472 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3473 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3474 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003475 cFYI(1, "Send error in QPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003476 } else { /* decode response */
3477 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3478
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003479 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3480 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04003481 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003482 rc = -EIO; /* bad smb */
Jeff Layton820a8032011-05-04 08:05:26 -04003483 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
Steve French50c2f752007-07-13 00:33:32 +00003484 rc = -EIO; /* 24 or 26 expected but we do not read
3485 last field */
3486 else if (pFindData) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003487 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003488 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00003489
3490 /* On legacy responses we do not read the last field,
3491 EAsize, fortunately since it varies by subdialect and
3492 also note it differs on Set vs. Get, ie two bytes or 4
3493 bytes depending but we don't care here */
3494 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003495 size = sizeof(FILE_INFO_STANDARD);
3496 else
3497 size = sizeof(FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003498 memcpy((char *) pFindData,
3499 (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003500 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003501 } else
3502 rc = -ENOMEM;
3503 }
3504 cifs_buf_release(pSMB);
3505 if (rc == -EAGAIN)
3506 goto QPathInfoRetry;
3507
3508 return rc;
3509}
3510
3511int
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003512CIFSSMBUnixQFileInfo(const int xid, struct cifsTconInfo *tcon,
3513 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
3514{
3515 struct smb_t2_qfi_req *pSMB = NULL;
3516 struct smb_t2_qfi_rsp *pSMBr = NULL;
3517 int rc = 0;
3518 int bytes_returned;
3519 __u16 params, byte_count;
3520
3521UnixQFileInfoRetry:
3522 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3523 (void **) &pSMBr);
3524 if (rc)
3525 return rc;
3526
3527 params = 2 /* level */ + 2 /* fid */;
3528 pSMB->t2.TotalDataCount = 0;
3529 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3530 /* BB find exact max data count below from sess structure BB */
3531 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3532 pSMB->t2.MaxSetupCount = 0;
3533 pSMB->t2.Reserved = 0;
3534 pSMB->t2.Flags = 0;
3535 pSMB->t2.Timeout = 0;
3536 pSMB->t2.Reserved2 = 0;
3537 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3538 Fid) - 4);
3539 pSMB->t2.DataCount = 0;
3540 pSMB->t2.DataOffset = 0;
3541 pSMB->t2.SetupCount = 1;
3542 pSMB->t2.Reserved3 = 0;
3543 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3544 byte_count = params + 1 /* pad */ ;
3545 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3546 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3547 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3548 pSMB->Pad = 0;
3549 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003550 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003551
3552 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3553 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3554 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00003555 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003556 } else { /* decode response */
3557 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3558
Jeff Layton820a8032011-05-04 08:05:26 -04003559 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Steve Frenchf19159d2010-04-21 04:12:10 +00003560 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response.\n"
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003561 "Unix Extensions can be disabled on mount "
Steve Frenchf19159d2010-04-21 04:12:10 +00003562 "by specifying the nosfu mount option.");
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003563 rc = -EIO; /* bad smb */
3564 } else {
3565 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3566 memcpy((char *) pFindData,
3567 (char *) &pSMBr->hdr.Protocol +
3568 data_offset,
3569 sizeof(FILE_UNIX_BASIC_INFO));
3570 }
3571 }
3572
3573 cifs_buf_release(pSMB);
3574 if (rc == -EAGAIN)
3575 goto UnixQFileInfoRetry;
3576
3577 return rc;
3578}
3579
3580int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003581CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3582 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00003583 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07003584 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003585{
3586/* SMB_QUERY_FILE_UNIX_BASIC */
3587 TRANSACTION2_QPI_REQ *pSMB = NULL;
3588 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3589 int rc = 0;
3590 int bytes_returned = 0;
3591 int name_len;
3592 __u16 params, byte_count;
3593
Joe Perchesb6b38f72010-04-21 03:50:45 +00003594 cFYI(1, "In QPathInfo (Unix) the path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003595UnixQPathInfoRetry:
3596 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3597 (void **) &pSMBr);
3598 if (rc)
3599 return rc;
3600
3601 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3602 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003603 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003604 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003605 name_len++; /* trailing null */
3606 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003607 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003608 name_len = strnlen(searchName, PATH_MAX);
3609 name_len++; /* trailing null */
3610 strncpy(pSMB->FileName, searchName, name_len);
3611 }
3612
Steve French50c2f752007-07-13 00:33:32 +00003613 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003614 pSMB->TotalDataCount = 0;
3615 pSMB->MaxParameterCount = cpu_to_le16(2);
3616 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00003617 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003618 pSMB->MaxSetupCount = 0;
3619 pSMB->Reserved = 0;
3620 pSMB->Flags = 0;
3621 pSMB->Timeout = 0;
3622 pSMB->Reserved2 = 0;
3623 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003624 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003625 pSMB->DataCount = 0;
3626 pSMB->DataOffset = 0;
3627 pSMB->SetupCount = 1;
3628 pSMB->Reserved3 = 0;
3629 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3630 byte_count = params + 1 /* pad */ ;
3631 pSMB->TotalParameterCount = cpu_to_le16(params);
3632 pSMB->ParameterCount = pSMB->TotalParameterCount;
3633 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3634 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003635 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003636 pSMB->ByteCount = cpu_to_le16(byte_count);
3637
3638 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3639 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3640 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003641 cFYI(1, "Send error in QPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003642 } else { /* decode response */
3643 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3644
Jeff Layton820a8032011-05-04 08:05:26 -04003645 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003646 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response.\n"
Steve French1e71f252007-09-20 15:30:07 +00003647 "Unix Extensions can be disabled on mount "
Joe Perchesb6b38f72010-04-21 03:50:45 +00003648 "by specifying the nosfu mount option.");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003649 rc = -EIO; /* bad smb */
3650 } else {
3651 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3652 memcpy((char *) pFindData,
3653 (char *) &pSMBr->hdr.Protocol +
3654 data_offset,
Steve French630f3f02007-10-25 21:17:17 +00003655 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003656 }
3657 }
3658 cifs_buf_release(pSMB);
3659 if (rc == -EAGAIN)
3660 goto UnixQPathInfoRetry;
3661
3662 return rc;
3663}
3664
Linus Torvalds1da177e2005-04-16 15:20:36 -07003665/* xid, tcon, searchName and codepage are input parms, rest are returned */
3666int
3667CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003668 const char *searchName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003669 const struct nls_table *nls_codepage,
Steve French50c2f752007-07-13 00:33:32 +00003670 __u16 *pnetfid,
3671 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003672{
3673/* level 257 SMB_ */
3674 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3675 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00003676 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003677 int rc = 0;
3678 int bytes_returned = 0;
3679 int name_len;
3680 __u16 params, byte_count;
3681
Joe Perchesb6b38f72010-04-21 03:50:45 +00003682 cFYI(1, "In FindFirst for %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003683
3684findFirstRetry:
3685 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3686 (void **) &pSMBr);
3687 if (rc)
3688 return rc;
3689
3690 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3691 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003692 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003693 PATH_MAX, nls_codepage, remap);
3694 /* We can not add the asterik earlier in case
3695 it got remapped to 0xF03A as if it were part of the
3696 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003697 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07003698 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07003699 pSMB->FileName[name_len+1] = 0;
3700 pSMB->FileName[name_len+2] = '*';
3701 pSMB->FileName[name_len+3] = 0;
3702 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003703 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3704 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07003705 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003706 } else { /* BB add check for overrun of SMB buf BB */
3707 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003708/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00003709 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003710 free buffer exit; BB */
3711 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07003712 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07003713 pSMB->FileName[name_len+1] = '*';
3714 pSMB->FileName[name_len+2] = 0;
3715 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003716 }
3717
3718 params = 12 + name_len /* includes null */ ;
3719 pSMB->TotalDataCount = 0; /* no EAs */
3720 pSMB->MaxParameterCount = cpu_to_le16(10);
3721 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3722 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3723 pSMB->MaxSetupCount = 0;
3724 pSMB->Reserved = 0;
3725 pSMB->Flags = 0;
3726 pSMB->Timeout = 0;
3727 pSMB->Reserved2 = 0;
3728 byte_count = params + 1 /* pad */ ;
3729 pSMB->TotalParameterCount = cpu_to_le16(params);
3730 pSMB->ParameterCount = pSMB->TotalParameterCount;
3731 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00003732 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3733 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003734 pSMB->DataCount = 0;
3735 pSMB->DataOffset = 0;
3736 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3737 pSMB->Reserved3 = 0;
3738 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3739 pSMB->SearchAttributes =
3740 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3741 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00003742 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3743 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
Linus Torvalds1da177e2005-04-16 15:20:36 -07003744 CIFS_SEARCH_RETURN_RESUME);
3745 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3746
3747 /* BB what should we set StorageType to? Does it matter? BB */
3748 pSMB->SearchStorageType = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003749 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003750 pSMB->ByteCount = cpu_to_le16(byte_count);
3751
3752 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3753 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003754 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003755
Steve French88274812006-03-09 22:21:45 +00003756 if (rc) {/* BB add logic to retry regular search if Unix search
3757 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003758 /* BB Add code to handle unsupported level rc */
Joe Perchesb6b38f72010-04-21 03:50:45 +00003759 cFYI(1, "Error in FindFirst = %d", rc);
Steve French1982c342005-08-17 12:38:22 -07003760
Steve French88274812006-03-09 22:21:45 +00003761 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003762
3763 /* BB eventually could optimize out free and realloc of buf */
3764 /* for this case */
3765 if (rc == -EAGAIN)
3766 goto findFirstRetry;
3767 } else { /* decode response */
3768 /* BB remember to free buffer if error BB */
3769 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003770 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00003771 unsigned int lnoff;
3772
Linus Torvalds1da177e2005-04-16 15:20:36 -07003773 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00003774 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003775 else
Steve French4b18f2a2008-04-29 00:06:05 +00003776 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003777
3778 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003779 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00003780 psrch_inf->srch_entries_start =
3781 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003782 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003783 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3784 le16_to_cpu(pSMBr->t2.ParameterOffset));
3785
Steve French790fe572007-07-07 19:25:05 +00003786 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00003787 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003788 else
Steve French4b18f2a2008-04-29 00:06:05 +00003789 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003790
Steve French50c2f752007-07-13 00:33:32 +00003791 psrch_inf->entries_in_buffer =
3792 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00003793 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003794 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00003795 lnoff = le16_to_cpu(parms->LastNameOffset);
3796 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3797 lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003798 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00003799 psrch_inf->last_entry = NULL;
3800 return rc;
3801 }
3802
Steve French0752f152008-10-07 20:03:33 +00003803 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00003804 lnoff;
3805
Linus Torvalds1da177e2005-04-16 15:20:36 -07003806 *pnetfid = parms->SearchHandle;
3807 } else {
3808 cifs_buf_release(pSMB);
3809 }
3810 }
3811
3812 return rc;
3813}
3814
3815int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003816 __u16 searchHandle, struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003817{
3818 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3819 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00003820 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003821 char *response_data;
3822 int rc = 0;
3823 int bytes_returned, name_len;
3824 __u16 params, byte_count;
3825
Joe Perchesb6b38f72010-04-21 03:50:45 +00003826 cFYI(1, "In FindNext");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003827
Steve French4b18f2a2008-04-29 00:06:05 +00003828 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003829 return -ENOENT;
3830
3831 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3832 (void **) &pSMBr);
3833 if (rc)
3834 return rc;
3835
Steve French50c2f752007-07-13 00:33:32 +00003836 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003837 byte_count = 0;
3838 pSMB->TotalDataCount = 0; /* no EAs */
3839 pSMB->MaxParameterCount = cpu_to_le16(8);
3840 pSMB->MaxDataCount =
Steve French50c2f752007-07-13 00:33:32 +00003841 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
3842 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003843 pSMB->MaxSetupCount = 0;
3844 pSMB->Reserved = 0;
3845 pSMB->Flags = 0;
3846 pSMB->Timeout = 0;
3847 pSMB->Reserved2 = 0;
3848 pSMB->ParameterOffset = cpu_to_le16(
3849 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3850 pSMB->DataCount = 0;
3851 pSMB->DataOffset = 0;
3852 pSMB->SetupCount = 1;
3853 pSMB->Reserved3 = 0;
3854 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3855 pSMB->SearchHandle = searchHandle; /* always kept as le */
3856 pSMB->SearchCount =
Steve French630f3f02007-10-25 21:17:17 +00003857 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003858 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3859 pSMB->ResumeKey = psrch_inf->resume_key;
3860 pSMB->SearchFlags =
3861 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3862
3863 name_len = psrch_inf->resume_name_len;
3864 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00003865 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003866 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3867 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07003868 /* 14 byte parm len above enough for 2 byte null terminator */
3869 pSMB->ResumeFileName[name_len] = 0;
3870 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003871 } else {
3872 rc = -EINVAL;
3873 goto FNext2_err_exit;
3874 }
3875 byte_count = params + 1 /* pad */ ;
3876 pSMB->TotalParameterCount = cpu_to_le16(params);
3877 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003878 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003879 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00003880
Linus Torvalds1da177e2005-04-16 15:20:36 -07003881 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3882 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003883 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003884 if (rc) {
3885 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00003886 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07003887 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00003888 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003889 } else
Joe Perchesb6b38f72010-04-21 03:50:45 +00003890 cFYI(1, "FindNext returned = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003891 } else { /* decode response */
3892 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00003893
Steve French790fe572007-07-07 19:25:05 +00003894 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00003895 unsigned int lnoff;
3896
Linus Torvalds1da177e2005-04-16 15:20:36 -07003897 /* BB fixme add lock for file (srch_info) struct here */
3898 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00003899 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003900 else
Steve French4b18f2a2008-04-29 00:06:05 +00003901 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003902 response_data = (char *) &pSMBr->hdr.Protocol +
3903 le16_to_cpu(pSMBr->t2.ParameterOffset);
3904 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3905 response_data = (char *)&pSMBr->hdr.Protocol +
3906 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00003907 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00003908 cifs_small_buf_release(
3909 psrch_inf->ntwrk_buf_start);
3910 else
3911 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003912 psrch_inf->srch_entries_start = response_data;
3913 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003914 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00003915 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00003916 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003917 else
Steve French4b18f2a2008-04-29 00:06:05 +00003918 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00003919 psrch_inf->entries_in_buffer =
3920 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003921 psrch_inf->index_of_last_entry +=
3922 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00003923 lnoff = le16_to_cpu(parms->LastNameOffset);
3924 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3925 lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003926 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00003927 psrch_inf->last_entry = NULL;
3928 return rc;
3929 } else
3930 psrch_inf->last_entry =
3931 psrch_inf->srch_entries_start + lnoff;
3932
Joe Perchesb6b38f72010-04-21 03:50:45 +00003933/* cFYI(1, "fnxt2 entries in buf %d index_of_last %d",
3934 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003935
3936 /* BB fixme add unlock here */
3937 }
3938
3939 }
3940
3941 /* BB On error, should we leave previous search buf (and count and
3942 last entry fields) intact or free the previous one? */
3943
3944 /* Note: On -EAGAIN error only caller can retry on handle based calls
3945 since file handle passed in no longer valid */
3946FNext2_err_exit:
3947 if (rc != 0)
3948 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003949 return rc;
3950}
3951
3952int
Steve French50c2f752007-07-13 00:33:32 +00003953CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
3954 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003955{
3956 int rc = 0;
3957 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003958
Joe Perchesb6b38f72010-04-21 03:50:45 +00003959 cFYI(1, "In CIFSSMBFindClose");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003960 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3961
3962 /* no sense returning error if session restarted
3963 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00003964 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003965 return 0;
3966 if (rc)
3967 return rc;
3968
Linus Torvalds1da177e2005-04-16 15:20:36 -07003969 pSMB->FileID = searchHandle;
3970 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00003971 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003972 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003973 cERROR(1, "Send error in FindClose = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00003974
Steve Frencha4544342005-08-24 13:59:35 -07003975 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003976
3977 /* Since session is dead, search handle closed on server already */
3978 if (rc == -EAGAIN)
3979 rc = 0;
3980
3981 return rc;
3982}
3983
Linus Torvalds1da177e2005-04-16 15:20:36 -07003984int
3985CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003986 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003987 __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00003988 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003989{
3990 int rc = 0;
3991 TRANSACTION2_QPI_REQ *pSMB = NULL;
3992 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3993 int name_len, bytes_returned;
3994 __u16 params, byte_count;
3995
Joe Perchesb6b38f72010-04-21 03:50:45 +00003996 cFYI(1, "In GetSrvInodeNum for %s", searchName);
Steve French790fe572007-07-07 19:25:05 +00003997 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00003998 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003999
4000GetInodeNumberRetry:
4001 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004002 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004003 if (rc)
4004 return rc;
4005
Linus Torvalds1da177e2005-04-16 15:20:36 -07004006 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4007 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004008 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French50c2f752007-07-13 00:33:32 +00004009 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004010 name_len++; /* trailing null */
4011 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004012 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004013 name_len = strnlen(searchName, PATH_MAX);
4014 name_len++; /* trailing null */
4015 strncpy(pSMB->FileName, searchName, name_len);
4016 }
4017
4018 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4019 pSMB->TotalDataCount = 0;
4020 pSMB->MaxParameterCount = cpu_to_le16(2);
4021 /* BB find exact max data count below from sess structure BB */
4022 pSMB->MaxDataCount = cpu_to_le16(4000);
4023 pSMB->MaxSetupCount = 0;
4024 pSMB->Reserved = 0;
4025 pSMB->Flags = 0;
4026 pSMB->Timeout = 0;
4027 pSMB->Reserved2 = 0;
4028 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004029 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004030 pSMB->DataCount = 0;
4031 pSMB->DataOffset = 0;
4032 pSMB->SetupCount = 1;
4033 pSMB->Reserved3 = 0;
4034 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4035 byte_count = params + 1 /* pad */ ;
4036 pSMB->TotalParameterCount = cpu_to_le16(params);
4037 pSMB->ParameterCount = pSMB->TotalParameterCount;
4038 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4039 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004040 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004041 pSMB->ByteCount = cpu_to_le16(byte_count);
4042
4043 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4044 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4045 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004046 cFYI(1, "error %d in QueryInternalInfo", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004047 } else {
4048 /* decode response */
4049 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004050 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04004051 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004052 /* If rc should we check for EOPNOSUPP and
4053 disable the srvino flag? or in caller? */
4054 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00004055 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004056 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4057 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00004058 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004059 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00004060 if (count < 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004061 cFYI(1, "Illegal size ret in QryIntrnlInf");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004062 rc = -EIO;
4063 goto GetInodeNumOut;
4064 }
4065 pfinfo = (struct file_internal_info *)
4066 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00004067 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004068 }
4069 }
4070GetInodeNumOut:
4071 cifs_buf_release(pSMB);
4072 if (rc == -EAGAIN)
4073 goto GetInodeNumberRetry;
4074 return rc;
4075}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004076
Igor Mammedovfec45852008-05-16 13:06:30 +04004077/* parses DFS refferal V3 structure
4078 * caller is responsible for freeing target_nodes
4079 * returns:
4080 * on success - 0
4081 * on failure - errno
4082 */
4083static int
Steve Frencha1fe78f2008-05-16 18:48:38 +00004084parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
Igor Mammedovfec45852008-05-16 13:06:30 +04004085 unsigned int *num_of_nodes,
4086 struct dfs_info3_param **target_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004087 const struct nls_table *nls_codepage, int remap,
4088 const char *searchName)
Igor Mammedovfec45852008-05-16 13:06:30 +04004089{
4090 int i, rc = 0;
4091 char *data_end;
4092 bool is_unicode;
4093 struct dfs_referral_level_3 *ref;
4094
Harvey Harrison5ca33c62008-07-23 17:45:58 -07004095 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4096 is_unicode = true;
4097 else
4098 is_unicode = false;
Igor Mammedovfec45852008-05-16 13:06:30 +04004099 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
4100
4101 if (*num_of_nodes < 1) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004102 cERROR(1, "num_referrals: must be at least > 0,"
4103 "but we get num_referrals = %d\n", *num_of_nodes);
Igor Mammedovfec45852008-05-16 13:06:30 +04004104 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004105 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004106 }
4107
4108 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
Al Viro1d92cfd2008-06-02 10:59:02 +01004109 if (ref->VersionNumber != cpu_to_le16(3)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004110 cERROR(1, "Referrals of V%d version are not supported,"
4111 "should be V3", le16_to_cpu(ref->VersionNumber));
Igor Mammedovfec45852008-05-16 13:06:30 +04004112 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004113 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004114 }
4115
4116 /* get the upper boundary of the resp buffer */
4117 data_end = (char *)(&(pSMBr->PathConsumed)) +
4118 le16_to_cpu(pSMBr->t2.DataCount);
4119
Steve Frenchf19159d2010-04-21 04:12:10 +00004120 cFYI(1, "num_referrals: %d dfs flags: 0x%x ...\n",
Igor Mammedovfec45852008-05-16 13:06:30 +04004121 *num_of_nodes,
Joe Perchesb6b38f72010-04-21 03:50:45 +00004122 le32_to_cpu(pSMBr->DFSFlags));
Igor Mammedovfec45852008-05-16 13:06:30 +04004123
4124 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
4125 *num_of_nodes, GFP_KERNEL);
4126 if (*target_nodes == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004127 cERROR(1, "Failed to allocate buffer for target_nodes\n");
Igor Mammedovfec45852008-05-16 13:06:30 +04004128 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004129 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004130 }
4131
Daniel Mack3ad2f3f2010-02-03 08:01:28 +08004132 /* collect necessary data from referrals */
Igor Mammedovfec45852008-05-16 13:06:30 +04004133 for (i = 0; i < *num_of_nodes; i++) {
4134 char *temp;
4135 int max_len;
4136 struct dfs_info3_param *node = (*target_nodes)+i;
4137
Steve French0e0d2cf2009-05-01 05:27:32 +00004138 node->flags = le32_to_cpu(pSMBr->DFSFlags);
Igor Mammedov2c556082008-10-23 13:58:42 +04004139 if (is_unicode) {
Jeff Layton331c3132008-12-17 06:31:53 -05004140 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4141 GFP_KERNEL);
Steve French2920ee22009-08-31 15:27:26 +00004142 if (tmp == NULL) {
4143 rc = -ENOMEM;
4144 goto parse_DFS_referrals_exit;
4145 }
Igor Mammedov2c556082008-10-23 13:58:42 +04004146 cifsConvertToUCS((__le16 *) tmp, searchName,
4147 PATH_MAX, nls_codepage, remap);
Jeff Layton69f801f2009-04-30 06:46:32 -04004148 node->path_consumed = cifs_ucs2_bytes(tmp,
4149 le16_to_cpu(pSMBr->PathConsumed),
Igor Mammedov2c556082008-10-23 13:58:42 +04004150 nls_codepage);
4151 kfree(tmp);
4152 } else
4153 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4154
Igor Mammedovfec45852008-05-16 13:06:30 +04004155 node->server_type = le16_to_cpu(ref->ServerType);
4156 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4157
4158 /* copy DfsPath */
4159 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4160 max_len = data_end - temp;
Steve Frenchd185cda2009-04-30 17:45:10 +00004161 node->path_name = cifs_strndup_from_ucs(temp, max_len,
4162 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004163 if (!node->path_name) {
4164 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004165 goto parse_DFS_referrals_exit;
Jeff Layton066ce682009-04-30 07:16:14 -04004166 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004167
4168 /* copy link target UNC */
4169 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4170 max_len = data_end - temp;
Steve Frenchd185cda2009-04-30 17:45:10 +00004171 node->node_name = cifs_strndup_from_ucs(temp, max_len,
4172 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004173 if (!node->node_name)
4174 rc = -ENOMEM;
Igor Mammedovfec45852008-05-16 13:06:30 +04004175 }
4176
Steve Frencha1fe78f2008-05-16 18:48:38 +00004177parse_DFS_referrals_exit:
Igor Mammedovfec45852008-05-16 13:06:30 +04004178 if (rc) {
4179 free_dfs_info_array(*target_nodes, *num_of_nodes);
4180 *target_nodes = NULL;
4181 *num_of_nodes = 0;
4182 }
4183 return rc;
4184}
4185
Linus Torvalds1da177e2005-04-16 15:20:36 -07004186int
4187CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
4188 const unsigned char *searchName,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004189 struct dfs_info3_param **target_nodes,
4190 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004191 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004192{
4193/* TRANS2_GET_DFS_REFERRAL */
4194 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4195 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004196 int rc = 0;
4197 int bytes_returned;
4198 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004199 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004200 *num_of_nodes = 0;
4201 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004202
Joe Perchesb6b38f72010-04-21 03:50:45 +00004203 cFYI(1, "In GetDFSRefer the path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004204 if (ses == NULL)
4205 return -ENODEV;
4206getDFSRetry:
4207 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4208 (void **) &pSMBr);
4209 if (rc)
4210 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004211
4212 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004213 but should never be null here anyway */
4214 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004215 pSMB->hdr.Tid = ses->ipc_tid;
4216 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004217 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004218 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004219 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004220 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004221
4222 if (ses->capabilities & CAP_UNICODE) {
4223 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4224 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004225 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07004226 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004227 name_len++; /* trailing null */
4228 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004229 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004230 name_len = strnlen(searchName, PATH_MAX);
4231 name_len++; /* trailing null */
4232 strncpy(pSMB->RequestFileName, searchName, name_len);
4233 }
4234
Steve French790fe572007-07-07 19:25:05 +00004235 if (ses->server) {
4236 if (ses->server->secMode &
Steve French1a4e15a2006-10-12 21:33:51 +00004237 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4238 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4239 }
4240
Steve French50c2f752007-07-13 00:33:32 +00004241 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004242
Linus Torvalds1da177e2005-04-16 15:20:36 -07004243 params = 2 /* level */ + name_len /*includes null */ ;
4244 pSMB->TotalDataCount = 0;
4245 pSMB->DataCount = 0;
4246 pSMB->DataOffset = 0;
4247 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004248 /* BB find exact max SMB PDU from sess structure BB */
4249 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004250 pSMB->MaxSetupCount = 0;
4251 pSMB->Reserved = 0;
4252 pSMB->Flags = 0;
4253 pSMB->Timeout = 0;
4254 pSMB->Reserved2 = 0;
4255 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004256 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004257 pSMB->SetupCount = 1;
4258 pSMB->Reserved3 = 0;
4259 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4260 byte_count = params + 3 /* pad */ ;
4261 pSMB->ParameterCount = cpu_to_le16(params);
4262 pSMB->TotalParameterCount = pSMB->ParameterCount;
4263 pSMB->MaxReferralLevel = cpu_to_le16(3);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004264 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004265 pSMB->ByteCount = cpu_to_le16(byte_count);
4266
4267 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4268 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4269 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004270 cFYI(1, "Send error in GetDFSRefer = %d", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004271 goto GetDFSRefExit;
4272 }
4273 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004274
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004275 /* BB Also check if enough total bytes returned? */
Jeff Layton820a8032011-05-04 08:05:26 -04004276 if (rc || get_bcc(&pSMBr->hdr) < 17) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004277 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004278 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004279 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004280
Joe Perchesb6b38f72010-04-21 03:50:45 +00004281 cFYI(1, "Decoding GetDFSRefer response BCC: %d Offset %d",
Jeff Layton820a8032011-05-04 08:05:26 -04004282 get_bcc(&pSMBr->hdr),
Joe Perchesb6b38f72010-04-21 03:50:45 +00004283 le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04004284
4285 /* parse returned result into more usable form */
Steve Frencha1fe78f2008-05-16 18:48:38 +00004286 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004287 target_nodes, nls_codepage, remap,
4288 searchName);
Igor Mammedovfec45852008-05-16 13:06:30 +04004289
Linus Torvalds1da177e2005-04-16 15:20:36 -07004290GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004291 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004292
4293 if (rc == -EAGAIN)
4294 goto getDFSRetry;
4295
4296 return rc;
4297}
4298
Steve French20962432005-09-21 22:05:57 -07004299/* Query File System Info such as free space to old servers such as Win 9x */
4300int
4301SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4302{
4303/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4304 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4305 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4306 FILE_SYSTEM_ALLOC_INFO *response_data;
4307 int rc = 0;
4308 int bytes_returned = 0;
4309 __u16 params, byte_count;
4310
Joe Perchesb6b38f72010-04-21 03:50:45 +00004311 cFYI(1, "OldQFSInfo");
Steve French20962432005-09-21 22:05:57 -07004312oldQFSInfoRetry:
4313 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4314 (void **) &pSMBr);
4315 if (rc)
4316 return rc;
Steve French20962432005-09-21 22:05:57 -07004317
4318 params = 2; /* level */
4319 pSMB->TotalDataCount = 0;
4320 pSMB->MaxParameterCount = cpu_to_le16(2);
4321 pSMB->MaxDataCount = cpu_to_le16(1000);
4322 pSMB->MaxSetupCount = 0;
4323 pSMB->Reserved = 0;
4324 pSMB->Flags = 0;
4325 pSMB->Timeout = 0;
4326 pSMB->Reserved2 = 0;
4327 byte_count = params + 1 /* pad */ ;
4328 pSMB->TotalParameterCount = cpu_to_le16(params);
4329 pSMB->ParameterCount = pSMB->TotalParameterCount;
4330 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4331 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4332 pSMB->DataCount = 0;
4333 pSMB->DataOffset = 0;
4334 pSMB->SetupCount = 1;
4335 pSMB->Reserved3 = 0;
4336 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4337 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004338 inc_rfc1001_len(pSMB, byte_count);
Steve French20962432005-09-21 22:05:57 -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);
4343 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004344 cFYI(1, "Send error in QFSInfo = %d", rc);
Steve French20962432005-09-21 22:05:57 -07004345 } else { /* decode response */
4346 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4347
Jeff Layton820a8032011-05-04 08:05:26 -04004348 if (rc || get_bcc(&pSMBr->hdr) < 18)
Steve French20962432005-09-21 22:05:57 -07004349 rc = -EIO; /* bad smb */
4350 else {
4351 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004352 cFYI(1, "qfsinf resp BCC: %d Offset %d",
Jeff Layton820a8032011-05-04 08:05:26 -04004353 get_bcc(&pSMBr->hdr), data_offset);
Steve French20962432005-09-21 22:05:57 -07004354
Steve French50c2f752007-07-13 00:33:32 +00004355 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004356 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4357 FSData->f_bsize =
4358 le16_to_cpu(response_data->BytesPerSector) *
4359 le32_to_cpu(response_data->
4360 SectorsPerAllocationUnit);
4361 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004362 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004363 FSData->f_bfree = FSData->f_bavail =
4364 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004365 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
4366 (unsigned long long)FSData->f_blocks,
4367 (unsigned long long)FSData->f_bfree,
4368 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07004369 }
4370 }
4371 cifs_buf_release(pSMB);
4372
4373 if (rc == -EAGAIN)
4374 goto oldQFSInfoRetry;
4375
4376 return rc;
4377}
4378
Linus Torvalds1da177e2005-04-16 15:20:36 -07004379int
Steve French737b7582005-04-28 22:41:06 -07004380CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004381{
4382/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4383 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4384 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4385 FILE_SYSTEM_INFO *response_data;
4386 int rc = 0;
4387 int bytes_returned = 0;
4388 __u16 params, byte_count;
4389
Joe Perchesb6b38f72010-04-21 03:50:45 +00004390 cFYI(1, "In QFSInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004391QFSInfoRetry:
4392 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4393 (void **) &pSMBr);
4394 if (rc)
4395 return rc;
4396
4397 params = 2; /* level */
4398 pSMB->TotalDataCount = 0;
4399 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004400 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004401 pSMB->MaxSetupCount = 0;
4402 pSMB->Reserved = 0;
4403 pSMB->Flags = 0;
4404 pSMB->Timeout = 0;
4405 pSMB->Reserved2 = 0;
4406 byte_count = params + 1 /* pad */ ;
4407 pSMB->TotalParameterCount = cpu_to_le16(params);
4408 pSMB->ParameterCount = pSMB->TotalParameterCount;
4409 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004410 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004411 pSMB->DataCount = 0;
4412 pSMB->DataOffset = 0;
4413 pSMB->SetupCount = 1;
4414 pSMB->Reserved3 = 0;
4415 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4416 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004417 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004418 pSMB->ByteCount = cpu_to_le16(byte_count);
4419
4420 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4421 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4422 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004423 cFYI(1, "Send error in QFSInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004424 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00004425 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004426
Jeff Layton820a8032011-05-04 08:05:26 -04004427 if (rc || get_bcc(&pSMBr->hdr) < 24)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004428 rc = -EIO; /* bad smb */
4429 else {
4430 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004431
4432 response_data =
4433 (FILE_SYSTEM_INFO
4434 *) (((char *) &pSMBr->hdr.Protocol) +
4435 data_offset);
4436 FSData->f_bsize =
4437 le32_to_cpu(response_data->BytesPerSector) *
4438 le32_to_cpu(response_data->
4439 SectorsPerAllocationUnit);
4440 FSData->f_blocks =
4441 le64_to_cpu(response_data->TotalAllocationUnits);
4442 FSData->f_bfree = FSData->f_bavail =
4443 le64_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004444 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
4445 (unsigned long long)FSData->f_blocks,
4446 (unsigned long long)FSData->f_bfree,
4447 FSData->f_bsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004448 }
4449 }
4450 cifs_buf_release(pSMB);
4451
4452 if (rc == -EAGAIN)
4453 goto QFSInfoRetry;
4454
4455 return rc;
4456}
4457
4458int
Steve French737b7582005-04-28 22:41:06 -07004459CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004460{
4461/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4462 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4463 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4464 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4465 int rc = 0;
4466 int bytes_returned = 0;
4467 __u16 params, byte_count;
4468
Joe Perchesb6b38f72010-04-21 03:50:45 +00004469 cFYI(1, "In QFSAttributeInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004470QFSAttributeRetry:
4471 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4472 (void **) &pSMBr);
4473 if (rc)
4474 return rc;
4475
4476 params = 2; /* level */
4477 pSMB->TotalDataCount = 0;
4478 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004479 /* BB find exact max SMB PDU from sess structure BB */
4480 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004481 pSMB->MaxSetupCount = 0;
4482 pSMB->Reserved = 0;
4483 pSMB->Flags = 0;
4484 pSMB->Timeout = 0;
4485 pSMB->Reserved2 = 0;
4486 byte_count = params + 1 /* pad */ ;
4487 pSMB->TotalParameterCount = cpu_to_le16(params);
4488 pSMB->ParameterCount = pSMB->TotalParameterCount;
4489 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004490 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004491 pSMB->DataCount = 0;
4492 pSMB->DataOffset = 0;
4493 pSMB->SetupCount = 1;
4494 pSMB->Reserved3 = 0;
4495 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4496 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004497 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004498 pSMB->ByteCount = cpu_to_le16(byte_count);
4499
4500 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4501 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4502 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004503 cERROR(1, "Send error in QFSAttributeInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004504 } else { /* decode response */
4505 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4506
Jeff Layton820a8032011-05-04 08:05:26 -04004507 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Steve French50c2f752007-07-13 00:33:32 +00004508 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004509 rc = -EIO; /* bad smb */
4510 } else {
4511 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4512 response_data =
4513 (FILE_SYSTEM_ATTRIBUTE_INFO
4514 *) (((char *) &pSMBr->hdr.Protocol) +
4515 data_offset);
4516 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004517 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004518 }
4519 }
4520 cifs_buf_release(pSMB);
4521
4522 if (rc == -EAGAIN)
4523 goto QFSAttributeRetry;
4524
4525 return rc;
4526}
4527
4528int
Steve French737b7582005-04-28 22:41:06 -07004529CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004530{
4531/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4532 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4533 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4534 FILE_SYSTEM_DEVICE_INFO *response_data;
4535 int rc = 0;
4536 int bytes_returned = 0;
4537 __u16 params, byte_count;
4538
Joe Perchesb6b38f72010-04-21 03:50:45 +00004539 cFYI(1, "In QFSDeviceInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004540QFSDeviceRetry:
4541 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4542 (void **) &pSMBr);
4543 if (rc)
4544 return rc;
4545
4546 params = 2; /* level */
4547 pSMB->TotalDataCount = 0;
4548 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004549 /* BB find exact max SMB PDU from sess structure BB */
4550 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004551 pSMB->MaxSetupCount = 0;
4552 pSMB->Reserved = 0;
4553 pSMB->Flags = 0;
4554 pSMB->Timeout = 0;
4555 pSMB->Reserved2 = 0;
4556 byte_count = params + 1 /* pad */ ;
4557 pSMB->TotalParameterCount = cpu_to_le16(params);
4558 pSMB->ParameterCount = pSMB->TotalParameterCount;
4559 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004560 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004561
4562 pSMB->DataCount = 0;
4563 pSMB->DataOffset = 0;
4564 pSMB->SetupCount = 1;
4565 pSMB->Reserved3 = 0;
4566 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4567 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004568 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004569 pSMB->ByteCount = cpu_to_le16(byte_count);
4570
4571 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4572 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4573 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004574 cFYI(1, "Send error in QFSDeviceInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004575 } else { /* decode response */
4576 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4577
Jeff Layton820a8032011-05-04 08:05:26 -04004578 if (rc || get_bcc(&pSMBr->hdr) <
4579 sizeof(FILE_SYSTEM_DEVICE_INFO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004580 rc = -EIO; /* bad smb */
4581 else {
4582 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4583 response_data =
Steve French737b7582005-04-28 22:41:06 -07004584 (FILE_SYSTEM_DEVICE_INFO *)
4585 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004586 data_offset);
4587 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004588 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004589 }
4590 }
4591 cifs_buf_release(pSMB);
4592
4593 if (rc == -EAGAIN)
4594 goto QFSDeviceRetry;
4595
4596 return rc;
4597}
4598
4599int
Steve French737b7582005-04-28 22:41:06 -07004600CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004601{
4602/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4603 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4604 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4605 FILE_SYSTEM_UNIX_INFO *response_data;
4606 int rc = 0;
4607 int bytes_returned = 0;
4608 __u16 params, byte_count;
4609
Joe Perchesb6b38f72010-04-21 03:50:45 +00004610 cFYI(1, "In QFSUnixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004611QFSUnixRetry:
Jeff Laytonf5695992010-09-29 15:27:08 -04004612 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
4613 (void **) &pSMB, (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004614 if (rc)
4615 return rc;
4616
4617 params = 2; /* level */
4618 pSMB->TotalDataCount = 0;
4619 pSMB->DataCount = 0;
4620 pSMB->DataOffset = 0;
4621 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004622 /* BB find exact max SMB PDU from sess structure BB */
4623 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004624 pSMB->MaxSetupCount = 0;
4625 pSMB->Reserved = 0;
4626 pSMB->Flags = 0;
4627 pSMB->Timeout = 0;
4628 pSMB->Reserved2 = 0;
4629 byte_count = params + 1 /* pad */ ;
4630 pSMB->ParameterCount = cpu_to_le16(params);
4631 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004632 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4633 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004634 pSMB->SetupCount = 1;
4635 pSMB->Reserved3 = 0;
4636 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4637 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004638 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004639 pSMB->ByteCount = cpu_to_le16(byte_count);
4640
4641 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4642 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4643 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004644 cERROR(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004645 } else { /* decode response */
4646 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4647
Jeff Layton820a8032011-05-04 08:05:26 -04004648 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004649 rc = -EIO; /* bad smb */
4650 } else {
4651 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4652 response_data =
4653 (FILE_SYSTEM_UNIX_INFO
4654 *) (((char *) &pSMBr->hdr.Protocol) +
4655 data_offset);
4656 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004657 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004658 }
4659 }
4660 cifs_buf_release(pSMB);
4661
4662 if (rc == -EAGAIN)
4663 goto QFSUnixRetry;
4664
4665
4666 return rc;
4667}
4668
Jeremy Allisonac670552005-06-22 17:26:35 -07004669int
Steve French45abc6e2005-06-23 13:42:03 -05004670CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07004671{
4672/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4673 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4674 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4675 int rc = 0;
4676 int bytes_returned = 0;
4677 __u16 params, param_offset, offset, byte_count;
4678
Joe Perchesb6b38f72010-04-21 03:50:45 +00004679 cFYI(1, "In SETFSUnixInfo");
Jeremy Allisonac670552005-06-22 17:26:35 -07004680SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00004681 /* BB switch to small buf init to save memory */
Jeff Laytonf5695992010-09-29 15:27:08 -04004682 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
4683 (void **) &pSMB, (void **) &pSMBr);
Jeremy Allisonac670552005-06-22 17:26:35 -07004684 if (rc)
4685 return rc;
4686
4687 params = 4; /* 2 bytes zero followed by info level. */
4688 pSMB->MaxSetupCount = 0;
4689 pSMB->Reserved = 0;
4690 pSMB->Flags = 0;
4691 pSMB->Timeout = 0;
4692 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00004693 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4694 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07004695 offset = param_offset + params;
4696
4697 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00004698 /* BB find exact max SMB PDU from sess structure BB */
4699 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07004700 pSMB->SetupCount = 1;
4701 pSMB->Reserved3 = 0;
4702 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4703 byte_count = 1 /* pad */ + params + 12;
4704
4705 pSMB->DataCount = cpu_to_le16(12);
4706 pSMB->ParameterCount = cpu_to_le16(params);
4707 pSMB->TotalDataCount = pSMB->DataCount;
4708 pSMB->TotalParameterCount = pSMB->ParameterCount;
4709 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4710 pSMB->DataOffset = cpu_to_le16(offset);
4711
4712 /* Params. */
4713 pSMB->FileNum = 0;
4714 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4715
4716 /* Data. */
4717 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4718 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4719 pSMB->ClientUnixCap = cpu_to_le64(cap);
4720
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004721 inc_rfc1001_len(pSMB, byte_count);
Jeremy Allisonac670552005-06-22 17:26:35 -07004722 pSMB->ByteCount = cpu_to_le16(byte_count);
4723
4724 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4725 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4726 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004727 cERROR(1, "Send error in SETFSUnixInfo = %d", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07004728 } else { /* decode response */
4729 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00004730 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07004731 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07004732 }
4733 cifs_buf_release(pSMB);
4734
4735 if (rc == -EAGAIN)
4736 goto SETFSUnixRetry;
4737
4738 return rc;
4739}
4740
4741
Linus Torvalds1da177e2005-04-16 15:20:36 -07004742
4743int
4744CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004745 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004746{
4747/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4748 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4749 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4750 FILE_SYSTEM_POSIX_INFO *response_data;
4751 int rc = 0;
4752 int bytes_returned = 0;
4753 __u16 params, byte_count;
4754
Joe Perchesb6b38f72010-04-21 03:50:45 +00004755 cFYI(1, "In QFSPosixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004756QFSPosixRetry:
4757 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4758 (void **) &pSMBr);
4759 if (rc)
4760 return rc;
4761
4762 params = 2; /* level */
4763 pSMB->TotalDataCount = 0;
4764 pSMB->DataCount = 0;
4765 pSMB->DataOffset = 0;
4766 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004767 /* BB find exact max SMB PDU from sess structure BB */
4768 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004769 pSMB->MaxSetupCount = 0;
4770 pSMB->Reserved = 0;
4771 pSMB->Flags = 0;
4772 pSMB->Timeout = 0;
4773 pSMB->Reserved2 = 0;
4774 byte_count = params + 1 /* pad */ ;
4775 pSMB->ParameterCount = cpu_to_le16(params);
4776 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004777 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4778 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004779 pSMB->SetupCount = 1;
4780 pSMB->Reserved3 = 0;
4781 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4782 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004783 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004784 pSMB->ByteCount = cpu_to_le16(byte_count);
4785
4786 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4787 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4788 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004789 cFYI(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004790 } else { /* decode response */
4791 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4792
Jeff Layton820a8032011-05-04 08:05:26 -04004793 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004794 rc = -EIO; /* bad smb */
4795 } else {
4796 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4797 response_data =
4798 (FILE_SYSTEM_POSIX_INFO
4799 *) (((char *) &pSMBr->hdr.Protocol) +
4800 data_offset);
4801 FSData->f_bsize =
4802 le32_to_cpu(response_data->BlockSize);
4803 FSData->f_blocks =
4804 le64_to_cpu(response_data->TotalBlocks);
4805 FSData->f_bfree =
4806 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00004807 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004808 FSData->f_bavail = FSData->f_bfree;
4809 } else {
4810 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00004811 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004812 }
Steve French790fe572007-07-07 19:25:05 +00004813 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004814 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00004815 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00004816 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004817 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00004818 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004819 }
4820 }
4821 cifs_buf_release(pSMB);
4822
4823 if (rc == -EAGAIN)
4824 goto QFSPosixRetry;
4825
4826 return rc;
4827}
4828
4829
Steve French50c2f752007-07-13 00:33:32 +00004830/* We can not use write of zero bytes trick to
4831 set file size due to need for large file support. Also note that
4832 this SetPathInfo is preferred to SetFileInfo based method in next
Linus Torvalds1da177e2005-04-16 15:20:36 -07004833 routine which is only needed to work around a sharing violation bug
4834 in Samba which this routine can run into */
4835
4836int
4837CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French4b18f2a2008-04-29 00:06:05 +00004838 __u64 size, bool SetAllocation,
Steve French737b7582005-04-28 22:41:06 -07004839 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004840{
4841 struct smb_com_transaction2_spi_req *pSMB = NULL;
4842 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4843 struct file_end_of_file_info *parm_data;
4844 int name_len;
4845 int rc = 0;
4846 int bytes_returned = 0;
4847 __u16 params, byte_count, data_count, param_offset, offset;
4848
Joe Perchesb6b38f72010-04-21 03:50:45 +00004849 cFYI(1, "In SetEOF");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004850SetEOFRetry:
4851 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4852 (void **) &pSMBr);
4853 if (rc)
4854 return rc;
4855
4856 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4857 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004858 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004859 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004860 name_len++; /* trailing null */
4861 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004862 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004863 name_len = strnlen(fileName, PATH_MAX);
4864 name_len++; /* trailing null */
4865 strncpy(pSMB->FileName, fileName, name_len);
4866 }
4867 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00004868 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004869 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07004870 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004871 pSMB->MaxSetupCount = 0;
4872 pSMB->Reserved = 0;
4873 pSMB->Flags = 0;
4874 pSMB->Timeout = 0;
4875 pSMB->Reserved2 = 0;
4876 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00004877 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004878 offset = param_offset + params;
Steve French790fe572007-07-07 19:25:05 +00004879 if (SetAllocation) {
Steve French50c2f752007-07-13 00:33:32 +00004880 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4881 pSMB->InformationLevel =
4882 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4883 else
4884 pSMB->InformationLevel =
4885 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4886 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004887 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4888 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004889 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004890 else
4891 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004892 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004893 }
4894
4895 parm_data =
4896 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4897 offset);
4898 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4899 pSMB->DataOffset = cpu_to_le16(offset);
4900 pSMB->SetupCount = 1;
4901 pSMB->Reserved3 = 0;
4902 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4903 byte_count = 3 /* pad */ + params + data_count;
4904 pSMB->DataCount = cpu_to_le16(data_count);
4905 pSMB->TotalDataCount = pSMB->DataCount;
4906 pSMB->ParameterCount = cpu_to_le16(params);
4907 pSMB->TotalParameterCount = pSMB->ParameterCount;
4908 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004909 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004910 parm_data->FileSize = cpu_to_le64(size);
4911 pSMB->ByteCount = cpu_to_le16(byte_count);
4912 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4913 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004914 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00004915 cFYI(1, "SetPathInfo (file size) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004916
4917 cifs_buf_release(pSMB);
4918
4919 if (rc == -EAGAIN)
4920 goto SetEOFRetry;
4921
4922 return rc;
4923}
4924
4925int
Steve French50c2f752007-07-13 00:33:32 +00004926CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
Steve French4b18f2a2008-04-29 00:06:05 +00004927 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004928{
4929 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004930 struct file_end_of_file_info *parm_data;
4931 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004932 __u16 params, param_offset, offset, byte_count, count;
4933
Joe Perchesb6b38f72010-04-21 03:50:45 +00004934 cFYI(1, "SetFileSize (via SetFileInfo) %lld",
4935 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07004936 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4937
Linus Torvalds1da177e2005-04-16 15:20:36 -07004938 if (rc)
4939 return rc;
4940
4941 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4942 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00004943
Linus Torvalds1da177e2005-04-16 15:20:36 -07004944 params = 6;
4945 pSMB->MaxSetupCount = 0;
4946 pSMB->Reserved = 0;
4947 pSMB->Flags = 0;
4948 pSMB->Timeout = 0;
4949 pSMB->Reserved2 = 0;
4950 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4951 offset = param_offset + params;
4952
Linus Torvalds1da177e2005-04-16 15:20:36 -07004953 count = sizeof(struct file_end_of_file_info);
4954 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004955 /* BB find exact max SMB PDU from sess structure BB */
4956 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004957 pSMB->SetupCount = 1;
4958 pSMB->Reserved3 = 0;
4959 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4960 byte_count = 3 /* pad */ + params + count;
4961 pSMB->DataCount = cpu_to_le16(count);
4962 pSMB->ParameterCount = cpu_to_le16(params);
4963 pSMB->TotalDataCount = pSMB->DataCount;
4964 pSMB->TotalParameterCount = pSMB->ParameterCount;
4965 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4966 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00004967 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
4968 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004969 pSMB->DataOffset = cpu_to_le16(offset);
4970 parm_data->FileSize = cpu_to_le64(size);
4971 pSMB->Fid = fid;
Steve French790fe572007-07-07 19:25:05 +00004972 if (SetAllocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004973 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4974 pSMB->InformationLevel =
4975 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4976 else
4977 pSMB->InformationLevel =
4978 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00004979 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004980 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4981 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004982 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004983 else
4984 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004985 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004986 }
4987 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004988 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004989 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French133672e2007-11-13 22:41:37 +00004990 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004991 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004992 cFYI(1, "Send error in SetFileInfo (SetFileSize) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004993 }
4994
Steve French50c2f752007-07-13 00:33:32 +00004995 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004996 since file handle passed in no longer valid */
4997
4998 return rc;
4999}
5000
Steve French50c2f752007-07-13 00:33:32 +00005001/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07005002 an open handle, rather than by pathname - this is awkward due to
5003 potential access conflicts on the open, but it is unavoidable for these
5004 old servers since the only other choice is to go from 100 nanosecond DCE
5005 time and resort to the original setpathinfo level which takes the ancient
5006 DOS time format with 2 second granularity */
5007int
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005008CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon,
5009 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005010{
5011 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005012 char *data_offset;
5013 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005014 __u16 params, param_offset, offset, byte_count, count;
5015
Joe Perchesb6b38f72010-04-21 03:50:45 +00005016 cFYI(1, "Set Times (via SetFileInfo)");
Steve Frenchcd634992005-04-28 22:41:10 -07005017 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5018
Linus Torvalds1da177e2005-04-16 15:20:36 -07005019 if (rc)
5020 return rc;
5021
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005022 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5023 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005024
Linus Torvalds1da177e2005-04-16 15:20:36 -07005025 params = 6;
5026 pSMB->MaxSetupCount = 0;
5027 pSMB->Reserved = 0;
5028 pSMB->Flags = 0;
5029 pSMB->Timeout = 0;
5030 pSMB->Reserved2 = 0;
5031 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5032 offset = param_offset + params;
5033
Steve French50c2f752007-07-13 00:33:32 +00005034 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005035
Steve French26f57362007-08-30 22:09:15 +00005036 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005037 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005038 /* BB find max SMB PDU from sess */
5039 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005040 pSMB->SetupCount = 1;
5041 pSMB->Reserved3 = 0;
5042 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5043 byte_count = 3 /* pad */ + params + count;
5044 pSMB->DataCount = cpu_to_le16(count);
5045 pSMB->ParameterCount = cpu_to_le16(params);
5046 pSMB->TotalDataCount = pSMB->DataCount;
5047 pSMB->TotalParameterCount = pSMB->ParameterCount;
5048 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5049 pSMB->DataOffset = cpu_to_le16(offset);
5050 pSMB->Fid = fid;
5051 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5052 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5053 else
5054 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5055 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005056 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005057 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005058 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Steve French133672e2007-11-13 22:41:37 +00005059 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005060 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005061 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005062
Steve French50c2f752007-07-13 00:33:32 +00005063 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005064 since file handle passed in no longer valid */
5065
5066 return rc;
5067}
5068
Jeff Layton6d22f092008-09-23 11:48:35 -04005069int
5070CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon,
5071 bool delete_file, __u16 fid, __u32 pid_of_opener)
5072{
5073 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5074 char *data_offset;
5075 int rc = 0;
5076 __u16 params, param_offset, offset, byte_count, count;
5077
Joe Perchesb6b38f72010-04-21 03:50:45 +00005078 cFYI(1, "Set File Disposition (via SetFileInfo)");
Jeff Layton6d22f092008-09-23 11:48:35 -04005079 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5080
5081 if (rc)
5082 return rc;
5083
5084 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5085 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5086
5087 params = 6;
5088 pSMB->MaxSetupCount = 0;
5089 pSMB->Reserved = 0;
5090 pSMB->Flags = 0;
5091 pSMB->Timeout = 0;
5092 pSMB->Reserved2 = 0;
5093 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5094 offset = param_offset + params;
5095
5096 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5097
5098 count = 1;
5099 pSMB->MaxParameterCount = cpu_to_le16(2);
5100 /* BB find max SMB PDU from sess */
5101 pSMB->MaxDataCount = cpu_to_le16(1000);
5102 pSMB->SetupCount = 1;
5103 pSMB->Reserved3 = 0;
5104 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5105 byte_count = 3 /* pad */ + params + count;
5106 pSMB->DataCount = cpu_to_le16(count);
5107 pSMB->ParameterCount = cpu_to_le16(params);
5108 pSMB->TotalDataCount = pSMB->DataCount;
5109 pSMB->TotalParameterCount = pSMB->ParameterCount;
5110 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5111 pSMB->DataOffset = cpu_to_le16(offset);
5112 pSMB->Fid = fid;
5113 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5114 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005115 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton6d22f092008-09-23 11:48:35 -04005116 pSMB->ByteCount = cpu_to_le16(byte_count);
5117 *data_offset = delete_file ? 1 : 0;
5118 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
5119 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005120 cFYI(1, "Send error in SetFileDisposition = %d", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005121
5122 return rc;
5123}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005124
5125int
Jeff Layton6fc000e2008-08-02 07:26:12 -04005126CIFSSMBSetPathInfo(const int xid, struct cifsTconInfo *tcon,
5127 const char *fileName, const FILE_BASIC_INFO *data,
5128 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005129{
5130 TRANSACTION2_SPI_REQ *pSMB = NULL;
5131 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5132 int name_len;
5133 int rc = 0;
5134 int bytes_returned = 0;
5135 char *data_offset;
5136 __u16 params, param_offset, offset, byte_count, count;
5137
Joe Perchesb6b38f72010-04-21 03:50:45 +00005138 cFYI(1, "In SetTimes");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005139
5140SetTimesRetry:
5141 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5142 (void **) &pSMBr);
5143 if (rc)
5144 return rc;
5145
5146 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5147 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05005148 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005149 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005150 name_len++; /* trailing null */
5151 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005152 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005153 name_len = strnlen(fileName, PATH_MAX);
5154 name_len++; /* trailing null */
5155 strncpy(pSMB->FileName, fileName, name_len);
5156 }
5157
5158 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005159 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005160 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005161 /* BB find max SMB PDU from sess structure BB */
5162 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005163 pSMB->MaxSetupCount = 0;
5164 pSMB->Reserved = 0;
5165 pSMB->Flags = 0;
5166 pSMB->Timeout = 0;
5167 pSMB->Reserved2 = 0;
5168 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005169 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005170 offset = param_offset + params;
5171 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5172 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5173 pSMB->DataOffset = cpu_to_le16(offset);
5174 pSMB->SetupCount = 1;
5175 pSMB->Reserved3 = 0;
5176 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5177 byte_count = 3 /* pad */ + params + count;
5178
5179 pSMB->DataCount = cpu_to_le16(count);
5180 pSMB->ParameterCount = cpu_to_le16(params);
5181 pSMB->TotalDataCount = pSMB->DataCount;
5182 pSMB->TotalParameterCount = pSMB->ParameterCount;
5183 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5184 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5185 else
5186 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5187 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005188 inc_rfc1001_len(pSMB, byte_count);
Steve French26f57362007-08-30 22:09:15 +00005189 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005190 pSMB->ByteCount = cpu_to_le16(byte_count);
5191 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5192 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005193 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005194 cFYI(1, "SetPathInfo (times) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005195
5196 cifs_buf_release(pSMB);
5197
5198 if (rc == -EAGAIN)
5199 goto SetTimesRetry;
5200
5201 return rc;
5202}
5203
5204/* Can not be used to set time stamps yet (due to old DOS time format) */
5205/* Can be used to set attributes */
5206#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5207 handling it anyway and NT4 was what we thought it would be needed for
5208 Do not delete it until we prove whether needed for Win9x though */
5209int
5210CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
5211 __u16 dos_attrs, const struct nls_table *nls_codepage)
5212{
5213 SETATTR_REQ *pSMB = NULL;
5214 SETATTR_RSP *pSMBr = NULL;
5215 int rc = 0;
5216 int bytes_returned;
5217 int name_len;
5218
Joe Perchesb6b38f72010-04-21 03:50:45 +00005219 cFYI(1, "In SetAttrLegacy");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005220
5221SetAttrLgcyRetry:
5222 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5223 (void **) &pSMBr);
5224 if (rc)
5225 return rc;
5226
5227 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5228 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005229 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005230 PATH_MAX, nls_codepage);
5231 name_len++; /* trailing null */
5232 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005233 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005234 name_len = strnlen(fileName, PATH_MAX);
5235 name_len++; /* trailing null */
5236 strncpy(pSMB->fileName, fileName, name_len);
5237 }
5238 pSMB->attr = cpu_to_le16(dos_attrs);
5239 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005240 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005241 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5242 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5243 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005244 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005245 cFYI(1, "Error in LegacySetAttr = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005246
5247 cifs_buf_release(pSMB);
5248
5249 if (rc == -EAGAIN)
5250 goto SetAttrLgcyRetry;
5251
5252 return rc;
5253}
5254#endif /* temporarily unneeded SetAttr legacy function */
5255
Jeff Layton654cf142009-07-09 20:02:49 -04005256static void
5257cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5258 const struct cifs_unix_set_info_args *args)
5259{
5260 u64 mode = args->mode;
5261
5262 /*
5263 * Samba server ignores set of file size to zero due to bugs in some
5264 * older clients, but we should be precise - we use SetFileSize to
5265 * set file size and do not want to truncate file size to zero
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005266 * accidentally as happened on one Samba server beta by putting
Jeff Layton654cf142009-07-09 20:02:49 -04005267 * zero instead of -1 here
5268 */
5269 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5270 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5271 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5272 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5273 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5274 data_offset->Uid = cpu_to_le64(args->uid);
5275 data_offset->Gid = cpu_to_le64(args->gid);
5276 /* better to leave device as zero when it is */
5277 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5278 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5279 data_offset->Permissions = cpu_to_le64(mode);
5280
5281 if (S_ISREG(mode))
5282 data_offset->Type = cpu_to_le32(UNIX_FILE);
5283 else if (S_ISDIR(mode))
5284 data_offset->Type = cpu_to_le32(UNIX_DIR);
5285 else if (S_ISLNK(mode))
5286 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5287 else if (S_ISCHR(mode))
5288 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5289 else if (S_ISBLK(mode))
5290 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5291 else if (S_ISFIFO(mode))
5292 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5293 else if (S_ISSOCK(mode))
5294 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5295}
5296
Linus Torvalds1da177e2005-04-16 15:20:36 -07005297int
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005298CIFSSMBUnixSetFileInfo(const int xid, struct cifsTconInfo *tcon,
5299 const struct cifs_unix_set_info_args *args,
5300 u16 fid, u32 pid_of_opener)
5301{
5302 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5303 FILE_UNIX_BASIC_INFO *data_offset;
5304 int rc = 0;
5305 u16 params, param_offset, offset, byte_count, count;
5306
Joe Perchesb6b38f72010-04-21 03:50:45 +00005307 cFYI(1, "Set Unix Info (via SetFileInfo)");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005308 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5309
5310 if (rc)
5311 return rc;
5312
5313 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5314 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5315
5316 params = 6;
5317 pSMB->MaxSetupCount = 0;
5318 pSMB->Reserved = 0;
5319 pSMB->Flags = 0;
5320 pSMB->Timeout = 0;
5321 pSMB->Reserved2 = 0;
5322 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5323 offset = param_offset + params;
5324
5325 data_offset = (FILE_UNIX_BASIC_INFO *)
5326 ((char *)(&pSMB->hdr.Protocol) + offset);
5327 count = sizeof(FILE_UNIX_BASIC_INFO);
5328
5329 pSMB->MaxParameterCount = cpu_to_le16(2);
5330 /* BB find max SMB PDU from sess */
5331 pSMB->MaxDataCount = cpu_to_le16(1000);
5332 pSMB->SetupCount = 1;
5333 pSMB->Reserved3 = 0;
5334 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5335 byte_count = 3 /* pad */ + params + count;
5336 pSMB->DataCount = cpu_to_le16(count);
5337 pSMB->ParameterCount = cpu_to_le16(params);
5338 pSMB->TotalDataCount = pSMB->DataCount;
5339 pSMB->TotalParameterCount = pSMB->ParameterCount;
5340 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5341 pSMB->DataOffset = cpu_to_le16(offset);
5342 pSMB->Fid = fid;
5343 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5344 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005345 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005346 pSMB->ByteCount = cpu_to_le16(byte_count);
5347
5348 cifs_fill_unix_set_info(data_offset, args);
5349
5350 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
5351 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005352 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005353
5354 /* Note: On -EAGAIN error only caller can retry on handle based calls
5355 since file handle passed in no longer valid */
5356
5357 return rc;
5358}
5359
5360int
Jeff Layton01ea95e2009-07-09 20:02:49 -04005361CIFSSMBUnixSetPathInfo(const int xid, struct cifsTconInfo *tcon, char *fileName,
5362 const struct cifs_unix_set_info_args *args,
5363 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005364{
5365 TRANSACTION2_SPI_REQ *pSMB = NULL;
5366 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5367 int name_len;
5368 int rc = 0;
5369 int bytes_returned = 0;
5370 FILE_UNIX_BASIC_INFO *data_offset;
5371 __u16 params, param_offset, offset, count, byte_count;
5372
Joe Perchesb6b38f72010-04-21 03:50:45 +00005373 cFYI(1, "In SetUID/GID/Mode");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005374setPermsRetry:
5375 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5376 (void **) &pSMBr);
5377 if (rc)
5378 return rc;
5379
5380 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5381 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005382 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005383 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005384 name_len++; /* trailing null */
5385 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005386 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005387 name_len = strnlen(fileName, PATH_MAX);
5388 name_len++; /* trailing null */
5389 strncpy(pSMB->FileName, fileName, name_len);
5390 }
5391
5392 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005393 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005394 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005395 /* BB find max SMB PDU from sess structure BB */
5396 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005397 pSMB->MaxSetupCount = 0;
5398 pSMB->Reserved = 0;
5399 pSMB->Flags = 0;
5400 pSMB->Timeout = 0;
5401 pSMB->Reserved2 = 0;
5402 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005403 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005404 offset = param_offset + params;
5405 data_offset =
5406 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5407 offset);
5408 memset(data_offset, 0, count);
5409 pSMB->DataOffset = cpu_to_le16(offset);
5410 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5411 pSMB->SetupCount = 1;
5412 pSMB->Reserved3 = 0;
5413 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5414 byte_count = 3 /* pad */ + params + count;
5415 pSMB->ParameterCount = cpu_to_le16(params);
5416 pSMB->DataCount = cpu_to_le16(count);
5417 pSMB->TotalParameterCount = pSMB->ParameterCount;
5418 pSMB->TotalDataCount = pSMB->DataCount;
5419 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5420 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005421 inc_rfc1001_len(pSMB, byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005422
Jeff Layton654cf142009-07-09 20:02:49 -04005423 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005424
5425 pSMB->ByteCount = cpu_to_le16(byte_count);
5426 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5427 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005428 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005429 cFYI(1, "SetPathInfo (perms) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005430
Steve French0d817bc2008-05-22 02:02:03 +00005431 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005432 if (rc == -EAGAIN)
5433 goto setPermsRetry;
5434 return rc;
5435}
5436
Linus Torvalds1da177e2005-04-16 15:20:36 -07005437#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05005438/*
5439 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
5440 * function used by listxattr and getxattr type calls. When ea_name is set,
5441 * it looks for that attribute name and stuffs that value into the EAData
5442 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
5443 * buffer. In both cases, the return value is either the length of the
5444 * resulting data or a negative error code. If EAData is a NULL pointer then
5445 * the data isn't copied to it, but the length is returned.
5446 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005447ssize_t
5448CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05005449 const unsigned char *searchName, const unsigned char *ea_name,
5450 char *EAData, size_t buf_size,
5451 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005452{
5453 /* BB assumes one setup word */
5454 TRANSACTION2_QPI_REQ *pSMB = NULL;
5455 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5456 int rc = 0;
5457 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05005458 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005459 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00005460 struct fea *temp_fea;
5461 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05005462 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005463 __u16 params, byte_count, data_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005464
Joe Perchesb6b38f72010-04-21 03:50:45 +00005465 cFYI(1, "In Query All EAs path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005466QAllEAsRetry:
5467 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5468 (void **) &pSMBr);
5469 if (rc)
5470 return rc;
5471
5472 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05005473 list_len =
Steve French50c2f752007-07-13 00:33:32 +00005474 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005475 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05005476 list_len++; /* trailing null */
5477 list_len *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005478 } else { /* BB improve the check for buffer overruns BB */
Jeff Layton6e462b92010-02-10 16:18:26 -05005479 list_len = strnlen(searchName, PATH_MAX);
5480 list_len++; /* trailing null */
5481 strncpy(pSMB->FileName, searchName, list_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005482 }
5483
Jeff Layton6e462b92010-02-10 16:18:26 -05005484 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005485 pSMB->TotalDataCount = 0;
5486 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005487 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05005488 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005489 pSMB->MaxSetupCount = 0;
5490 pSMB->Reserved = 0;
5491 pSMB->Flags = 0;
5492 pSMB->Timeout = 0;
5493 pSMB->Reserved2 = 0;
5494 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005495 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005496 pSMB->DataCount = 0;
5497 pSMB->DataOffset = 0;
5498 pSMB->SetupCount = 1;
5499 pSMB->Reserved3 = 0;
5500 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5501 byte_count = params + 1 /* pad */ ;
5502 pSMB->TotalParameterCount = cpu_to_le16(params);
5503 pSMB->ParameterCount = pSMB->TotalParameterCount;
5504 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5505 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005506 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005507 pSMB->ByteCount = cpu_to_le16(byte_count);
5508
5509 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5510 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5511 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005512 cFYI(1, "Send error in QueryAllEAs = %d", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05005513 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005514 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05005515
5516
5517 /* BB also check enough total bytes returned */
5518 /* BB we need to improve the validity checking
5519 of these trans2 responses */
5520
5521 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Jeff Layton820a8032011-05-04 08:05:26 -04005522 if (rc || get_bcc(&pSMBr->hdr) < 4) {
Jeff Laytonf0d38682010-02-10 16:18:26 -05005523 rc = -EIO; /* bad smb */
5524 goto QAllEAsOut;
5525 }
5526
5527 /* check that length of list is not more than bcc */
5528 /* check that each entry does not go beyond length
5529 of list */
5530 /* check that each element of each entry does not
5531 go beyond end of list */
5532 /* validate_trans2_offsets() */
5533 /* BB check if start of smb + data_offset > &bcc+ bcc */
5534
5535 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5536 ea_response_data = (struct fealist *)
5537 (((char *) &pSMBr->hdr.Protocol) + data_offset);
5538
Jeff Layton6e462b92010-02-10 16:18:26 -05005539 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesb6b38f72010-04-21 03:50:45 +00005540 cFYI(1, "ea length %d", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05005541 if (list_len <= 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005542 cFYI(1, "empty EA list returned from server");
Jeff Laytonf0d38682010-02-10 16:18:26 -05005543 goto QAllEAsOut;
5544 }
5545
Jeff Layton0cd126b2010-02-10 16:18:26 -05005546 /* make sure list_len doesn't go past end of SMB */
Jeff Layton690c5222011-01-20 13:36:51 -05005547 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
Jeff Layton0cd126b2010-02-10 16:18:26 -05005548 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005549 cFYI(1, "EA list appears to go beyond SMB");
Jeff Layton0cd126b2010-02-10 16:18:26 -05005550 rc = -EIO;
5551 goto QAllEAsOut;
5552 }
5553
Jeff Laytonf0d38682010-02-10 16:18:26 -05005554 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05005555 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005556 temp_fea = ea_response_data->list;
5557 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05005558 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00005559 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005560 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05005561
Jeff Layton6e462b92010-02-10 16:18:26 -05005562 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005563 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05005564 /* make sure we can read name_len and value_len */
5565 if (list_len < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005566 cFYI(1, "EA entry goes beyond length of list");
Jeff Layton0cd126b2010-02-10 16:18:26 -05005567 rc = -EIO;
5568 goto QAllEAsOut;
5569 }
5570
5571 name_len = temp_fea->name_len;
5572 value_len = le16_to_cpu(temp_fea->value_len);
5573 list_len -= name_len + 1 + value_len;
5574 if (list_len < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005575 cFYI(1, "EA entry goes beyond length of list");
Jeff Layton0cd126b2010-02-10 16:18:26 -05005576 rc = -EIO;
5577 goto QAllEAsOut;
5578 }
5579
Jeff Layton31c05192010-02-10 16:18:26 -05005580 if (ea_name) {
5581 if (strncmp(ea_name, temp_ptr, name_len) == 0) {
5582 temp_ptr += name_len + 1;
5583 rc = value_len;
5584 if (buf_size == 0)
5585 goto QAllEAsOut;
5586 if ((size_t)value_len > buf_size) {
5587 rc = -ERANGE;
5588 goto QAllEAsOut;
5589 }
5590 memcpy(EAData, temp_ptr, value_len);
5591 goto QAllEAsOut;
5592 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05005593 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05005594 /* account for prefix user. and trailing null */
5595 rc += (5 + 1 + name_len);
5596 if (rc < (int) buf_size) {
5597 memcpy(EAData, "user.", 5);
5598 EAData += 5;
5599 memcpy(EAData, temp_ptr, name_len);
5600 EAData += name_len;
5601 /* null terminate name */
5602 *EAData = 0;
5603 ++EAData;
5604 } else if (buf_size == 0) {
5605 /* skip copy - calc size only */
5606 } else {
5607 /* stop before overrun buffer */
5608 rc = -ERANGE;
5609 break;
5610 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05005611 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05005612 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005613 temp_fea = (struct fea *)temp_ptr;
5614 }
5615
Jeff Layton31c05192010-02-10 16:18:26 -05005616 /* didn't find the named attribute */
5617 if (ea_name)
5618 rc = -ENODATA;
5619
Jeff Laytonf0d38682010-02-10 16:18:26 -05005620QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00005621 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005622 if (rc == -EAGAIN)
5623 goto QAllEAsRetry;
5624
5625 return (ssize_t)rc;
5626}
5627
Linus Torvalds1da177e2005-04-16 15:20:36 -07005628int
5629CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00005630 const char *ea_name, const void *ea_value,
5631 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5632 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005633{
5634 struct smb_com_transaction2_spi_req *pSMB = NULL;
5635 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5636 struct fealist *parm_data;
5637 int name_len;
5638 int rc = 0;
5639 int bytes_returned = 0;
5640 __u16 params, param_offset, byte_count, offset, count;
5641
Joe Perchesb6b38f72010-04-21 03:50:45 +00005642 cFYI(1, "In SetEA");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005643SetEARetry:
5644 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5645 (void **) &pSMBr);
5646 if (rc)
5647 return rc;
5648
5649 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5650 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005651 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005652 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005653 name_len++; /* trailing null */
5654 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005655 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005656 name_len = strnlen(fileName, PATH_MAX);
5657 name_len++; /* trailing null */
5658 strncpy(pSMB->FileName, fileName, name_len);
5659 }
5660
5661 params = 6 + name_len;
5662
5663 /* done calculating parms using name_len of file name,
5664 now use name_len to calculate length of ea name
5665 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00005666 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005667 name_len = 0;
5668 else
Steve French50c2f752007-07-13 00:33:32 +00005669 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005670
Steve Frenchdae5dbd2007-12-30 23:49:57 +00005671 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005672 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005673 /* BB find max SMB PDU from sess */
5674 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005675 pSMB->MaxSetupCount = 0;
5676 pSMB->Reserved = 0;
5677 pSMB->Flags = 0;
5678 pSMB->Timeout = 0;
5679 pSMB->Reserved2 = 0;
5680 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005681 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005682 offset = param_offset + params;
5683 pSMB->InformationLevel =
5684 cpu_to_le16(SMB_SET_FILE_EA);
5685
5686 parm_data =
5687 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5688 offset);
5689 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5690 pSMB->DataOffset = cpu_to_le16(offset);
5691 pSMB->SetupCount = 1;
5692 pSMB->Reserved3 = 0;
5693 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5694 byte_count = 3 /* pad */ + params + count;
5695 pSMB->DataCount = cpu_to_le16(count);
5696 parm_data->list_len = cpu_to_le32(count);
5697 parm_data->list[0].EA_flags = 0;
5698 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08005699 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005700 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00005701 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00005702 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005703 parm_data->list[0].name[name_len] = 0;
5704 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5705 /* caller ensures that ea_value_len is less than 64K but
5706 we need to ensure that it fits within the smb */
5707
Steve French50c2f752007-07-13 00:33:32 +00005708 /*BB add length check to see if it would fit in
5709 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00005710 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5711 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00005712 memcpy(parm_data->list[0].name+name_len+1,
5713 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005714
5715 pSMB->TotalDataCount = pSMB->DataCount;
5716 pSMB->ParameterCount = cpu_to_le16(params);
5717 pSMB->TotalParameterCount = pSMB->ParameterCount;
5718 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005719 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005720 pSMB->ByteCount = cpu_to_le16(byte_count);
5721 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5722 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005723 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005724 cFYI(1, "SetPathInfo (EA) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005725
5726 cifs_buf_release(pSMB);
5727
5728 if (rc == -EAGAIN)
5729 goto SetEARetry;
5730
5731 return rc;
5732}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005733#endif
Steve French0eff0e22011-02-24 05:39:23 +00005734
5735#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */
5736/*
5737 * Years ago the kernel added a "dnotify" function for Samba server,
5738 * to allow network clients (such as Windows) to display updated
5739 * lists of files in directory listings automatically when
5740 * files are added by one user when another user has the
5741 * same directory open on their desktop. The Linux cifs kernel
5742 * client hooked into the kernel side of this interface for
5743 * the same reason, but ironically when the VFS moved from
5744 * "dnotify" to "inotify" it became harder to plug in Linux
5745 * network file system clients (the most obvious use case
5746 * for notify interfaces is when multiple users can update
5747 * the contents of the same directory - exactly what network
5748 * file systems can do) although the server (Samba) could
5749 * still use it. For the short term we leave the worker
5750 * function ifdeffed out (below) until inotify is fixed
5751 * in the VFS to make it easier to plug in network file
5752 * system clients. If inotify turns out to be permanently
5753 * incompatible for network fs clients, we could instead simply
5754 * expose this config flag by adding a future cifs (and smb2) notify ioctl.
5755 */
5756int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
5757 const int notify_subdirs, const __u16 netfid,
5758 __u32 filter, struct file *pfile, int multishot,
5759 const struct nls_table *nls_codepage)
5760{
5761 int rc = 0;
5762 struct smb_com_transaction_change_notify_req *pSMB = NULL;
5763 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
5764 struct dir_notify_req *dnotify_req;
5765 int bytes_returned;
5766
5767 cFYI(1, "In CIFSSMBNotify for file handle %d", (int)netfid);
5768 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
5769 (void **) &pSMBr);
5770 if (rc)
5771 return rc;
5772
5773 pSMB->TotalParameterCount = 0 ;
5774 pSMB->TotalDataCount = 0;
5775 pSMB->MaxParameterCount = cpu_to_le32(2);
5776 /* BB find exact data count max from sess structure BB */
5777 pSMB->MaxDataCount = 0; /* same in little endian or be */
5778/* BB VERIFY verify which is correct for above BB */
5779 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
5780 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
5781
5782 pSMB->MaxSetupCount = 4;
5783 pSMB->Reserved = 0;
5784 pSMB->ParameterOffset = 0;
5785 pSMB->DataCount = 0;
5786 pSMB->DataOffset = 0;
5787 pSMB->SetupCount = 4; /* single byte does not need le conversion */
5788 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
5789 pSMB->ParameterCount = pSMB->TotalParameterCount;
5790 if (notify_subdirs)
5791 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
5792 pSMB->Reserved2 = 0;
5793 pSMB->CompletionFilter = cpu_to_le32(filter);
5794 pSMB->Fid = netfid; /* file handle always le */
5795 pSMB->ByteCount = 0;
5796
5797 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5798 (struct smb_hdr *)pSMBr, &bytes_returned,
5799 CIFS_ASYNC_OP);
5800 if (rc) {
5801 cFYI(1, "Error in Notify = %d", rc);
5802 } else {
5803 /* Add file to outstanding requests */
5804 /* BB change to kmem cache alloc */
5805 dnotify_req = kmalloc(
5806 sizeof(struct dir_notify_req),
5807 GFP_KERNEL);
5808 if (dnotify_req) {
5809 dnotify_req->Pid = pSMB->hdr.Pid;
5810 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
5811 dnotify_req->Mid = pSMB->hdr.Mid;
5812 dnotify_req->Tid = pSMB->hdr.Tid;
5813 dnotify_req->Uid = pSMB->hdr.Uid;
5814 dnotify_req->netfid = netfid;
5815 dnotify_req->pfile = pfile;
5816 dnotify_req->filter = filter;
5817 dnotify_req->multishot = multishot;
5818 spin_lock(&GlobalMid_Lock);
5819 list_add_tail(&dnotify_req->lhead,
5820 &GlobalDnotifyReqList);
5821 spin_unlock(&GlobalMid_Lock);
5822 } else
5823 rc = -ENOMEM;
5824 }
5825 cifs_buf_release(pSMB);
5826 return rc;
5827}
5828#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */