blob: e0d24135b3c69f400e96efedb180094be646f36d [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 Frenchb815f1e52006-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 Frenchb815f1e52006-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 Frenchb815f1e52006-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 Frenchb815f1e52006-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 Frenchb815f1e52006-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 Frenchb815f1e52006-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 Frenchb815f1e52006-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 Frenchb815f1e52006-10-02 05:53:29 +0000492 server->timeAdj = result;
Steve French25ee4a92006-09-30 00:54:23 +0000493 } else {
Steve Frenchb815f1e52006-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 Frenchb815f1e52006-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;
Jeff Laytonfcc31cb2011-05-19 16:22:53 -0400728 struct kvec iov;
Jeff Layton766fdbb2011-01-11 07:24:21 -0500729
730 cFYI(1, "In echo request");
731
732 rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
733 if (rc)
734 return rc;
735
736 /* set up echo request */
Steve French5443d132011-03-13 05:08:25 +0000737 smb->hdr.Tid = 0xffff;
Jeff Layton99d86c8f2011-01-20 21:19:25 -0500738 smb->hdr.WordCount = 1;
739 put_unaligned_le16(1, &smb->EchoCount);
Jeff Layton820a8032011-05-04 08:05:26 -0400740 put_bcc(1, &smb->hdr);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500741 smb->Data[0] = 'a';
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000742 inc_rfc1001_len(smb, 3);
Jeff Laytonfcc31cb2011-05-19 16:22:53 -0400743 iov.iov_base = smb;
744 iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
Jeff Layton766fdbb2011-01-11 07:24:21 -0500745
Jeff Layton59ffd842011-05-19 16:22:55 -0400746 rc = cifs_call_async(server, &iov, 1, cifs_echo_callback, server, true);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500747 if (rc)
748 cFYI(1, "Echo request failed: %d", rc);
749
750 cifs_small_buf_release(smb);
751
752 return rc;
753}
754
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755int
756CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
757{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758 LOGOFF_ANDX_REQ *pSMB;
759 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760
Joe Perchesb6b38f72010-04-21 03:50:45 +0000761 cFYI(1, "In SMBLogoff for session disconnect");
Jeff Layton14fbf502008-11-14 13:53:46 -0500762
763 /*
764 * BB: do we need to check validity of ses and server? They should
765 * always be valid since we have an active reference. If not, that
766 * should probably be a BUG()
767 */
768 if (!ses || !ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769 return -EIO;
770
Steve Frenchd7b619c2010-02-25 05:36:46 +0000771 mutex_lock(&ses->session_mutex);
Steve French3b795212008-11-13 19:45:32 +0000772 if (ses->need_reconnect)
773 goto session_already_dead; /* no need to send SMBlogoff if uid
774 already closed due to reconnect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
776 if (rc) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000777 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 return rc;
779 }
780
Steve French3b795212008-11-13 19:45:32 +0000781 pSMB->hdr.Mid = GetNextMid(ses->server);
Steve French1982c342005-08-17 12:38:22 -0700782
Steve French3b795212008-11-13 19:45:32 +0000783 if (ses->server->secMode &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
785 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786
787 pSMB->hdr.Uid = ses->Suid;
788
789 pSMB->AndXCommand = 0xFF;
Steve French133672e2007-11-13 22:41:37 +0000790 rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
Steve French3b795212008-11-13 19:45:32 +0000791session_already_dead:
Steve Frenchd7b619c2010-02-25 05:36:46 +0000792 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793
794 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000795 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 error */
797 if (rc == -EAGAIN)
798 rc = 0;
799 return rc;
800}
801
802int
Steve French2d785a52007-07-15 01:48:57 +0000803CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
804 __u16 type, const struct nls_table *nls_codepage, int remap)
805{
806 TRANSACTION2_SPI_REQ *pSMB = NULL;
807 TRANSACTION2_SPI_RSP *pSMBr = NULL;
808 struct unlink_psx_rq *pRqD;
809 int name_len;
810 int rc = 0;
811 int bytes_returned = 0;
812 __u16 params, param_offset, offset, byte_count;
813
Joe Perchesb6b38f72010-04-21 03:50:45 +0000814 cFYI(1, "In POSIX delete");
Steve French2d785a52007-07-15 01:48:57 +0000815PsxDelete:
816 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
817 (void **) &pSMBr);
818 if (rc)
819 return rc;
820
821 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
822 name_len =
823 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
824 PATH_MAX, nls_codepage, remap);
825 name_len++; /* trailing null */
826 name_len *= 2;
827 } else { /* BB add path length overrun check */
828 name_len = strnlen(fileName, PATH_MAX);
829 name_len++; /* trailing null */
830 strncpy(pSMB->FileName, fileName, name_len);
831 }
832
833 params = 6 + name_len;
834 pSMB->MaxParameterCount = cpu_to_le16(2);
835 pSMB->MaxDataCount = 0; /* BB double check this with jra */
836 pSMB->MaxSetupCount = 0;
837 pSMB->Reserved = 0;
838 pSMB->Flags = 0;
839 pSMB->Timeout = 0;
840 pSMB->Reserved2 = 0;
841 param_offset = offsetof(struct smb_com_transaction2_spi_req,
842 InformationLevel) - 4;
843 offset = param_offset + params;
844
845 /* Setup pointer to Request Data (inode type) */
846 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
847 pRqD->type = cpu_to_le16(type);
848 pSMB->ParameterOffset = cpu_to_le16(param_offset);
849 pSMB->DataOffset = cpu_to_le16(offset);
850 pSMB->SetupCount = 1;
851 pSMB->Reserved3 = 0;
852 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
853 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
854
855 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
856 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
857 pSMB->ParameterCount = cpu_to_le16(params);
858 pSMB->TotalParameterCount = pSMB->ParameterCount;
859 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
860 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000861 inc_rfc1001_len(pSMB, byte_count);
Steve French2d785a52007-07-15 01:48:57 +0000862 pSMB->ByteCount = cpu_to_le16(byte_count);
863 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
864 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000865 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000866 cFYI(1, "Posix delete returned %d", rc);
Steve French2d785a52007-07-15 01:48:57 +0000867 cifs_buf_release(pSMB);
868
869 cifs_stats_inc(&tcon->num_deletes);
870
871 if (rc == -EAGAIN)
872 goto PsxDelete;
873
874 return rc;
875}
876
877int
Steve French737b7582005-04-28 22:41:06 -0700878CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
879 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880{
881 DELETE_FILE_REQ *pSMB = NULL;
882 DELETE_FILE_RSP *pSMBr = NULL;
883 int rc = 0;
884 int bytes_returned;
885 int name_len;
886
887DelFileRetry:
888 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
889 (void **) &pSMBr);
890 if (rc)
891 return rc;
892
893 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
894 name_len =
Steve French50c2f752007-07-13 00:33:32 +0000895 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
Steve French737b7582005-04-28 22:41:06 -0700896 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 name_len++; /* trailing null */
898 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700899 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900 name_len = strnlen(fileName, PATH_MAX);
901 name_len++; /* trailing null */
902 strncpy(pSMB->fileName, fileName, name_len);
903 }
904 pSMB->SearchAttributes =
905 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
906 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000907 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908 pSMB->ByteCount = cpu_to_le16(name_len + 1);
909 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
910 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700911 cifs_stats_inc(&tcon->num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000912 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000913 cFYI(1, "Error in RMFile = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914
915 cifs_buf_release(pSMB);
916 if (rc == -EAGAIN)
917 goto DelFileRetry;
918
919 return rc;
920}
921
922int
Steve French50c2f752007-07-13 00:33:32 +0000923CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
Steve French737b7582005-04-28 22:41:06 -0700924 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925{
926 DELETE_DIRECTORY_REQ *pSMB = NULL;
927 DELETE_DIRECTORY_RSP *pSMBr = NULL;
928 int rc = 0;
929 int bytes_returned;
930 int name_len;
931
Joe Perchesb6b38f72010-04-21 03:50:45 +0000932 cFYI(1, "In CIFSSMBRmDir");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933RmDirRetry:
934 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
935 (void **) &pSMBr);
936 if (rc)
937 return rc;
938
939 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French737b7582005-04-28 22:41:06 -0700940 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
941 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942 name_len++; /* trailing null */
943 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700944 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945 name_len = strnlen(dirName, PATH_MAX);
946 name_len++; /* trailing null */
947 strncpy(pSMB->DirName, dirName, name_len);
948 }
949
950 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000951 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952 pSMB->ByteCount = cpu_to_le16(name_len + 1);
953 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
954 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700955 cifs_stats_inc(&tcon->num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000956 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000957 cFYI(1, "Error in RMDir = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958
959 cifs_buf_release(pSMB);
960 if (rc == -EAGAIN)
961 goto RmDirRetry;
962 return rc;
963}
964
965int
966CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -0700967 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968{
969 int rc = 0;
970 CREATE_DIRECTORY_REQ *pSMB = NULL;
971 CREATE_DIRECTORY_RSP *pSMBr = NULL;
972 int bytes_returned;
973 int name_len;
974
Joe Perchesb6b38f72010-04-21 03:50:45 +0000975 cFYI(1, "In CIFSSMBMkDir");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976MkDirRetry:
977 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
978 (void **) &pSMBr);
979 if (rc)
980 return rc;
981
982 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +0000983 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
Steve French737b7582005-04-28 22:41:06 -0700984 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985 name_len++; /* trailing null */
986 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700987 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988 name_len = strnlen(name, PATH_MAX);
989 name_len++; /* trailing null */
990 strncpy(pSMB->DirName, name, name_len);
991 }
992
993 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000994 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995 pSMB->ByteCount = cpu_to_le16(name_len + 1);
996 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
997 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700998 cifs_stats_inc(&tcon->num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000999 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001000 cFYI(1, "Error in Mkdir = %d", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07001001
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 cifs_buf_release(pSMB);
1003 if (rc == -EAGAIN)
1004 goto MkDirRetry;
1005 return rc;
1006}
1007
Steve French2dd29d32007-04-23 22:07:35 +00001008int
1009CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
Steve Frenchad7a2922008-02-07 23:25:02 +00001010 __u64 mode, __u16 *netfid, FILE_UNIX_BASIC_INFO *pRetData,
Steve French50c2f752007-07-13 00:33:32 +00001011 __u32 *pOplock, const char *name,
Steve French2dd29d32007-04-23 22:07:35 +00001012 const struct nls_table *nls_codepage, int remap)
1013{
1014 TRANSACTION2_SPI_REQ *pSMB = NULL;
1015 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1016 int name_len;
1017 int rc = 0;
1018 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001019 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +00001020 OPEN_PSX_REQ *pdata;
1021 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +00001022
Joe Perchesb6b38f72010-04-21 03:50:45 +00001023 cFYI(1, "In POSIX Create");
Steve French2dd29d32007-04-23 22:07:35 +00001024PsxCreat:
1025 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1026 (void **) &pSMBr);
1027 if (rc)
1028 return rc;
1029
1030 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1031 name_len =
1032 cifsConvertToUCS((__le16 *) pSMB->FileName, name,
1033 PATH_MAX, nls_codepage, remap);
1034 name_len++; /* trailing null */
1035 name_len *= 2;
1036 } else { /* BB improve the check for buffer overruns BB */
1037 name_len = strnlen(name, PATH_MAX);
1038 name_len++; /* trailing null */
1039 strncpy(pSMB->FileName, name, name_len);
1040 }
1041
1042 params = 6 + name_len;
1043 count = sizeof(OPEN_PSX_REQ);
1044 pSMB->MaxParameterCount = cpu_to_le16(2);
1045 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1046 pSMB->MaxSetupCount = 0;
1047 pSMB->Reserved = 0;
1048 pSMB->Flags = 0;
1049 pSMB->Timeout = 0;
1050 pSMB->Reserved2 = 0;
1051 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001052 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001053 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001054 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001055 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001056 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001057 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001058 pdata->OpenFlags = cpu_to_le32(*pOplock);
1059 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1060 pSMB->DataOffset = cpu_to_le16(offset);
1061 pSMB->SetupCount = 1;
1062 pSMB->Reserved3 = 0;
1063 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1064 byte_count = 3 /* pad */ + params + count;
1065
1066 pSMB->DataCount = cpu_to_le16(count);
1067 pSMB->ParameterCount = cpu_to_le16(params);
1068 pSMB->TotalDataCount = pSMB->DataCount;
1069 pSMB->TotalParameterCount = pSMB->ParameterCount;
1070 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1071 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001072 inc_rfc1001_len(pSMB, byte_count);
Steve French2dd29d32007-04-23 22:07:35 +00001073 pSMB->ByteCount = cpu_to_le16(byte_count);
1074 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1075 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1076 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001077 cFYI(1, "Posix create returned %d", rc);
Steve French2dd29d32007-04-23 22:07:35 +00001078 goto psx_create_err;
1079 }
1080
Joe Perchesb6b38f72010-04-21 03:50:45 +00001081 cFYI(1, "copying inode info");
Steve French2dd29d32007-04-23 22:07:35 +00001082 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1083
Jeff Layton820a8032011-05-04 08:05:26 -04001084 if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) {
Steve French2dd29d32007-04-23 22:07:35 +00001085 rc = -EIO; /* bad smb */
1086 goto psx_create_err;
1087 }
1088
1089 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001090 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001091 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001092
Steve French2dd29d32007-04-23 22:07:35 +00001093 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001094 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001095 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1096 /* Let caller know file was created so we can set the mode. */
1097 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001098 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001099 *pOplock |= CIFS_CREATE_ACTION;
1100 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001101 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1102 pRetData->Type = cpu_to_le32(-1); /* unknown */
Joe Perchesb6b38f72010-04-21 03:50:45 +00001103 cFYI(DBG2, "unknown type");
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001104 } else {
Jeff Layton820a8032011-05-04 08:05:26 -04001105 if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001106 + sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001107 cERROR(1, "Open response data too small");
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001108 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001109 goto psx_create_err;
1110 }
Steve French50c2f752007-07-13 00:33:32 +00001111 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001112 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001113 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001114 }
Steve French2dd29d32007-04-23 22:07:35 +00001115
1116psx_create_err:
1117 cifs_buf_release(pSMB);
1118
Steve French65bc98b2009-07-10 15:27:25 +00001119 if (posix_flags & SMB_O_DIRECTORY)
1120 cifs_stats_inc(&tcon->num_posixmkdirs);
1121 else
1122 cifs_stats_inc(&tcon->num_posixopens);
Steve French2dd29d32007-04-23 22:07:35 +00001123
1124 if (rc == -EAGAIN)
1125 goto PsxCreat;
1126
Steve French50c2f752007-07-13 00:33:32 +00001127 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001128}
1129
Steve Frencha9d02ad2005-08-24 23:06:05 -07001130static __u16 convert_disposition(int disposition)
1131{
1132 __u16 ofun = 0;
1133
1134 switch (disposition) {
1135 case FILE_SUPERSEDE:
1136 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1137 break;
1138 case FILE_OPEN:
1139 ofun = SMBOPEN_OAPPEND;
1140 break;
1141 case FILE_CREATE:
1142 ofun = SMBOPEN_OCREATE;
1143 break;
1144 case FILE_OPEN_IF:
1145 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1146 break;
1147 case FILE_OVERWRITE:
1148 ofun = SMBOPEN_OTRUNC;
1149 break;
1150 case FILE_OVERWRITE_IF:
1151 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1152 break;
1153 default:
Joe Perchesb6b38f72010-04-21 03:50:45 +00001154 cFYI(1, "unknown disposition %d", disposition);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001155 ofun = SMBOPEN_OAPPEND; /* regular open */
1156 }
1157 return ofun;
1158}
1159
Jeff Layton35fc37d2008-05-14 10:22:03 -07001160static int
1161access_flags_to_smbopen_mode(const int access_flags)
1162{
1163 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1164
1165 if (masked_flags == GENERIC_READ)
1166 return SMBOPEN_READ;
1167 else if (masked_flags == GENERIC_WRITE)
1168 return SMBOPEN_WRITE;
1169
1170 /* just go for read/write */
1171 return SMBOPEN_READWRITE;
1172}
1173
Steve Frencha9d02ad2005-08-24 23:06:05 -07001174int
1175SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
1176 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001177 const int access_flags, const int create_options, __u16 *netfid,
1178 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001179 const struct nls_table *nls_codepage, int remap)
1180{
1181 int rc = -EACCES;
1182 OPENX_REQ *pSMB = NULL;
1183 OPENX_RSP *pSMBr = NULL;
1184 int bytes_returned;
1185 int name_len;
1186 __u16 count;
1187
1188OldOpenRetry:
1189 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1190 (void **) &pSMBr);
1191 if (rc)
1192 return rc;
1193
1194 pSMB->AndXCommand = 0xFF; /* none */
1195
1196 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1197 count = 1; /* account for one byte pad to word boundary */
1198 name_len =
1199 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1200 fileName, PATH_MAX, nls_codepage, remap);
1201 name_len++; /* trailing null */
1202 name_len *= 2;
1203 } else { /* BB improve check for buffer overruns BB */
1204 count = 0; /* no pad */
1205 name_len = strnlen(fileName, PATH_MAX);
1206 name_len++; /* trailing null */
1207 strncpy(pSMB->fileName, fileName, name_len);
1208 }
1209 if (*pOplock & REQ_OPLOCK)
1210 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001211 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001212 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001213
Steve Frencha9d02ad2005-08-24 23:06:05 -07001214 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001215 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001216 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1217 /* set file as system file if special file such
1218 as fifo and server expecting SFU style and
1219 no Unix extensions */
1220
Steve French790fe572007-07-07 19:25:05 +00001221 if (create_options & CREATE_OPTION_SPECIAL)
1222 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001223 else /* BB FIXME BB */
1224 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001225
Jeff Layton67750fb2008-05-09 22:28:02 +00001226 if (create_options & CREATE_OPTION_READONLY)
1227 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001228
1229 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001230/* pSMB->CreateOptions = cpu_to_le32(create_options &
1231 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001232 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001233
1234 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001235 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001236 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001237 inc_rfc1001_len(pSMB, count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001238
1239 pSMB->ByteCount = cpu_to_le16(count);
1240 /* long_op set to 1 to allow for oplock break timeouts */
1241 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001242 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001243 cifs_stats_inc(&tcon->num_opens);
1244 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001245 cFYI(1, "Error in Open = %d", rc);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001246 } else {
1247 /* BB verify if wct == 15 */
1248
Steve French582d21e2008-05-13 04:54:12 +00001249/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001250
1251 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1252 /* Let caller know file was created so we can set the mode. */
1253 /* Do we care about the CreateAction in any other cases? */
1254 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001255/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001256 *pOplock |= CIFS_CREATE_ACTION; */
1257 /* BB FIXME END */
1258
Steve French790fe572007-07-07 19:25:05 +00001259 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001260 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1261 pfile_info->LastAccessTime = 0; /* BB fixme */
1262 pfile_info->LastWriteTime = 0; /* BB fixme */
1263 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001264 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001265 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001266 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001267 pfile_info->AllocationSize =
1268 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1269 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001270 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001271 pfile_info->DeletePending = 0;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001272 }
1273 }
1274
1275 cifs_buf_release(pSMB);
1276 if (rc == -EAGAIN)
1277 goto OldOpenRetry;
1278 return rc;
1279}
1280
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281int
1282CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1283 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001284 const int access_flags, const int create_options, __u16 *netfid,
1285 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001286 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287{
1288 int rc = -EACCES;
1289 OPEN_REQ *pSMB = NULL;
1290 OPEN_RSP *pSMBr = NULL;
1291 int bytes_returned;
1292 int name_len;
1293 __u16 count;
1294
1295openRetry:
1296 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1297 (void **) &pSMBr);
1298 if (rc)
1299 return rc;
1300
1301 pSMB->AndXCommand = 0xFF; /* none */
1302
1303 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1304 count = 1; /* account for one byte pad to word boundary */
1305 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001306 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -07001307 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308 name_len++; /* trailing null */
1309 name_len *= 2;
1310 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001311 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312 count = 0; /* no pad */
1313 name_len = strnlen(fileName, PATH_MAX);
1314 name_len++; /* trailing null */
1315 pSMB->NameLength = cpu_to_le16(name_len);
1316 strncpy(pSMB->fileName, fileName, name_len);
1317 }
1318 if (*pOplock & REQ_OPLOCK)
1319 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001320 else if (*pOplock & REQ_BATCHOPLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1323 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -07001324 /* set file as system file if special file such
1325 as fifo and server expecting SFU style and
1326 no Unix extensions */
Steve French790fe572007-07-07 19:25:05 +00001327 if (create_options & CREATE_OPTION_SPECIAL)
Steve Frencheda3c0292005-07-21 15:20:28 -07001328 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1329 else
1330 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Jeff Layton67750fb2008-05-09 22:28:02 +00001331
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332 /* XP does not handle ATTR_POSIX_SEMANTICS */
1333 /* but it helps speed up case sensitive checks for other
1334 servers such as Samba */
1335 if (tcon->ses->capabilities & CAP_UNIX)
1336 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1337
Jeff Layton67750fb2008-05-09 22:28:02 +00001338 if (create_options & CREATE_OPTION_READONLY)
1339 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1340
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1342 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -07001343 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001344 /* BB Expirement with various impersonation levels and verify */
1345 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346 pSMB->SecurityFlags =
1347 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1348
1349 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001350 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351
1352 pSMB->ByteCount = cpu_to_le16(count);
1353 /* long_op set to 1 to allow for oplock break timeouts */
1354 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001355 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001356 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001358 cFYI(1, "Error in Open = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359 } else {
Steve French09d1db52005-04-28 22:41:08 -07001360 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1362 /* Let caller know file was created so we can set the mode. */
1363 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001364 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve French50c2f752007-07-13 00:33:32 +00001365 *pOplock |= CIFS_CREATE_ACTION;
Steve French790fe572007-07-07 19:25:05 +00001366 if (pfile_info) {
Steve French61e74802008-12-03 00:57:54 +00001367 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1368 36 /* CreationTime to Attributes */);
1369 /* the file_info buf is endian converted by caller */
1370 pfile_info->AllocationSize = pSMBr->AllocationSize;
1371 pfile_info->EndOfFile = pSMBr->EndOfFile;
1372 pfile_info->NumberOfLinks = cpu_to_le32(1);
1373 pfile_info->DeletePending = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001376
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377 cifs_buf_release(pSMB);
1378 if (rc == -EAGAIN)
1379 goto openRetry;
1380 return rc;
1381}
1382
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383int
Steve French50c2f752007-07-13 00:33:32 +00001384CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
1385 const unsigned int count, const __u64 lseek, unsigned int *nbytes,
1386 char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387{
1388 int rc = -EACCES;
1389 READ_REQ *pSMB = NULL;
1390 READ_RSP *pSMBr = NULL;
1391 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001392 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001393 int resp_buf_type = 0;
1394 struct kvec iov[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395
Joe Perchesb6b38f72010-04-21 03:50:45 +00001396 cFYI(1, "Reading %d bytes on fid %d", count, netfid);
Steve French790fe572007-07-07 19:25:05 +00001397 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001398 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001399 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001400 wct = 10; /* old style read */
Steve French4c3130e2008-12-09 00:28:16 +00001401 if ((lseek >> 32) > 0) {
1402 /* can not handle this big offset for old */
1403 return -EIO;
1404 }
1405 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406
1407 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001408 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001409 if (rc)
1410 return rc;
1411
1412 /* tcon and ses pointer are checked in smb_init */
1413 if (tcon->ses->server == NULL)
1414 return -ECONNABORTED;
1415
Steve Frenchec637e32005-12-12 20:53:18 -08001416 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417 pSMB->Fid = netfid;
1418 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001419 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001420 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001421
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422 pSMB->Remaining = 0;
1423 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1424 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001425 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001426 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1427 else {
1428 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001429 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001430 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001431 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001432 }
Steve Frenchec637e32005-12-12 20:53:18 -08001433
1434 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001435 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve Frencha761ac52007-10-18 21:45:27 +00001436 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Jeff Layton77499812011-01-11 07:24:23 -05001437 &resp_buf_type, CIFS_LOG_ERROR);
Steve Frencha4544342005-08-24 13:59:35 -07001438 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001439 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001440 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001441 cERROR(1, "Send error in read = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442 } else {
1443 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1444 data_length = data_length << 16;
1445 data_length += le16_to_cpu(pSMBr->DataLength);
1446 *nbytes = data_length;
1447
1448 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001449 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001450 || (data_length > count)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001451 cFYI(1, "bad length %d for count %d",
1452 data_length, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453 rc = -EIO;
1454 *nbytes = 0;
1455 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001456 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001457 le16_to_cpu(pSMBr->DataOffset);
1458/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001459 cERROR(1, "Faulting on read rc = %d",rc);
Steve French50c2f752007-07-13 00:33:32 +00001460 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001461 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001462 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001463 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464 }
1465 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466
Steve French4b8f9302006-02-26 16:41:18 +00001467/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001468 if (*buf) {
1469 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001470 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001471 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001472 cifs_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001473 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001474 /* return buffer to caller to free */
1475 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001476 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001477 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001478 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001479 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001480 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001481
1482 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483 since file handle passed in no longer valid */
1484 return rc;
1485}
1486
Steve Frenchec637e32005-12-12 20:53:18 -08001487
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488int
1489CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1490 const int netfid, const unsigned int count,
1491 const __u64 offset, unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001492 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493{
1494 int rc = -EACCES;
1495 WRITE_REQ *pSMB = NULL;
1496 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001497 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498 __u32 bytes_sent;
1499 __u16 byte_count;
1500
Steve Frencha24e2d72010-04-03 17:20:21 +00001501 *nbytes = 0;
1502
Joe Perchesb6b38f72010-04-21 03:50:45 +00001503 /* cFYI(1, "write at %lld %d bytes", offset, count);*/
Steve French790fe572007-07-07 19:25:05 +00001504 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001505 return -ECONNABORTED;
1506
Steve French790fe572007-07-07 19:25:05 +00001507 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001508 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001509 else {
Steve French1c955182005-08-30 20:58:07 -07001510 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001511 if ((offset >> 32) > 0) {
1512 /* can not handle big offset for old srv */
1513 return -EIO;
1514 }
1515 }
Steve French1c955182005-08-30 20:58:07 -07001516
1517 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518 (void **) &pSMBr);
1519 if (rc)
1520 return rc;
1521 /* tcon and ses pointer are checked in smb_init */
1522 if (tcon->ses->server == NULL)
1523 return -ECONNABORTED;
1524
1525 pSMB->AndXCommand = 0xFF; /* none */
1526 pSMB->Fid = netfid;
1527 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001528 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001529 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001530
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531 pSMB->Reserved = 0xFFFFFFFF;
1532 pSMB->WriteMode = 0;
1533 pSMB->Remaining = 0;
1534
Steve French50c2f752007-07-13 00:33:32 +00001535 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536 can send more if LARGE_WRITE_X capability returned by the server and if
1537 our buffer is big enough or if we convert to iovecs on socket writes
1538 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001539 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1541 } else {
1542 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1543 & ~0xFF;
1544 }
1545
1546 if (bytes_sent > count)
1547 bytes_sent = count;
1548 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001549 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001550 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001551 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001552 else if (ubuf) {
1553 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554 cifs_buf_release(pSMB);
1555 return -EFAULT;
1556 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001557 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558 /* No buffer */
1559 cifs_buf_release(pSMB);
1560 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001561 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001562 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001563 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001564 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001565 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001566
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1568 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001569 inc_rfc1001_len(pSMB, byte_count);
Steve French1c955182005-08-30 20:58:07 -07001570
Steve French790fe572007-07-07 19:25:05 +00001571 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001572 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001573 else { /* old style write has byte count 4 bytes earlier
1574 so 4 bytes pad */
1575 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001576 (struct smb_com_writex_req *)pSMB;
1577 pSMBW->ByteCount = cpu_to_le16(byte_count);
1578 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579
1580 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1581 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001582 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00001584 cFYI(1, "Send error in write = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001585 } else {
1586 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1587 *nbytes = (*nbytes) << 16;
1588 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301589
1590 /*
1591 * Mask off high 16 bits when bytes written as returned by the
1592 * server is greater than bytes requested by the client. Some
1593 * OS/2 servers are known to set incorrect CountHigh values.
1594 */
1595 if (*nbytes > count)
1596 *nbytes &= 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597 }
1598
1599 cifs_buf_release(pSMB);
1600
Steve French50c2f752007-07-13 00:33:32 +00001601 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602 since file handle passed in no longer valid */
1603
1604 return rc;
1605}
1606
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001607int
1608CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609 const int netfid, const unsigned int count,
Steve French3e844692005-10-03 13:37:24 -07001610 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1611 int n_vec, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001612{
1613 int rc = -EACCES;
1614 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001615 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001616 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001617 int resp_buf_type = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001619 *nbytes = 0;
1620
Joe Perchesb6b38f72010-04-21 03:50:45 +00001621 cFYI(1, "write2 at %lld %d bytes", (long long)offset, count);
Steve Frenchff7feac2005-11-15 16:45:16 -08001622
Steve French4c3130e2008-12-09 00:28:16 +00001623 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07001624 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001625 } else {
Steve French8cc64c62005-10-03 13:49:43 -07001626 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001627 if ((offset >> 32) > 0) {
1628 /* can not handle big offset for old srv */
1629 return -EIO;
1630 }
1631 }
Steve French8cc64c62005-10-03 13:49:43 -07001632 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633 if (rc)
1634 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635 /* tcon and ses pointer are checked in smb_init */
1636 if (tcon->ses->server == NULL)
1637 return -ECONNABORTED;
1638
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001639 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640 pSMB->Fid = netfid;
1641 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001642 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001643 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001644 pSMB->Reserved = 0xFFFFFFFF;
1645 pSMB->WriteMode = 0;
1646 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001647
Linus Torvalds1da177e2005-04-16 15:20:36 -07001648 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001649 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650
Steve French3e844692005-10-03 13:37:24 -07001651 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1652 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001653 /* header + 1 byte pad */
1654 smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
Steve French790fe572007-07-07 19:25:05 +00001655 if (wct == 14)
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001656 inc_rfc1001_len(pSMB, count + 1);
Steve French8cc64c62005-10-03 13:49:43 -07001657 else /* wct == 12 */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001658 inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
Steve French790fe572007-07-07 19:25:05 +00001659 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001660 pSMB->ByteCount = cpu_to_le16(count + 1);
1661 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00001662 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07001663 (struct smb_com_writex_req *)pSMB;
1664 pSMBW->ByteCount = cpu_to_le16(count + 5);
1665 }
Steve French3e844692005-10-03 13:37:24 -07001666 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00001667 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08001668 iov[0].iov_len = smb_hdr_len + 4;
1669 else /* wct == 12 pad bigger by four bytes */
1670 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00001671
Steve French3e844692005-10-03 13:37:24 -07001672
Steve Frenchec637e32005-12-12 20:53:18 -08001673 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French133672e2007-11-13 22:41:37 +00001674 long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001675 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001676 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001677 cFYI(1, "Send error Write2 = %d", rc);
Steve French790fe572007-07-07 19:25:05 +00001678 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08001679 /* presumably this can not happen, but best to be safe */
1680 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001681 } else {
Steve Frenchad7a2922008-02-07 23:25:02 +00001682 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001683 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1684 *nbytes = (*nbytes) << 16;
1685 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301686
1687 /*
1688 * Mask off high 16 bits when bytes written as returned by the
1689 * server is greater than bytes requested by the client. OS/2
1690 * servers are known to set incorrect CountHigh values.
1691 */
1692 if (*nbytes > count)
1693 *nbytes &= 0xFFFF;
Steve French50c2f752007-07-13 00:33:32 +00001694 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695
Steve French4b8f9302006-02-26 16:41:18 +00001696/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001697 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001698 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001699 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001700 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701
Steve French50c2f752007-07-13 00:33:32 +00001702 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703 since file handle passed in no longer valid */
1704
1705 return rc;
1706}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001707
1708
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709int
1710CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1711 const __u16 smb_file_id, const __u64 len,
1712 const __u64 offset, const __u32 numUnlock,
Pavel Shilovsky12fed002011-01-17 20:15:44 +03001713 const __u32 numLock, const __u8 lockType,
1714 const bool waitFlag, const __u8 oplock_level)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715{
1716 int rc = 0;
1717 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00001718/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719 int bytes_returned;
1720 int timeout = 0;
1721 __u16 count;
1722
Joe Perchesb6b38f72010-04-21 03:50:45 +00001723 cFYI(1, "CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock);
Steve French46810cb2005-04-28 22:41:09 -07001724 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1725
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726 if (rc)
1727 return rc;
1728
Steve French790fe572007-07-07 19:25:05 +00001729 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Steve French133672e2007-11-13 22:41:37 +00001730 timeout = CIFS_ASYNC_OP; /* no response expected */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00001732 } else if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00001733 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1735 } else {
1736 pSMB->Timeout = 0;
1737 }
1738
1739 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1740 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1741 pSMB->LockType = lockType;
Pavel Shilovsky12fed002011-01-17 20:15:44 +03001742 pSMB->OplockLevel = oplock_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743 pSMB->AndXCommand = 0xFF; /* none */
1744 pSMB->Fid = smb_file_id; /* netfid stays le */
1745
Steve French790fe572007-07-07 19:25:05 +00001746 if ((numLock != 0) || (numUnlock != 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001747 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1748 /* BB where to store pid high? */
1749 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1750 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1751 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1752 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1753 count = sizeof(LOCKING_ANDX_RANGE);
1754 } else {
1755 /* oplock break */
1756 count = 0;
1757 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001758 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759 pSMB->ByteCount = cpu_to_le16(count);
1760
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001761 if (waitFlag) {
1762 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00001763 (struct smb_hdr *) pSMB, &bytes_returned);
Steve French133672e2007-11-13 22:41:37 +00001764 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001765 } else {
Steve French133672e2007-11-13 22:41:37 +00001766 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
1767 timeout);
1768 /* SMB buffer freed by function above */
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001769 }
Steve Frencha4544342005-08-24 13:59:35 -07001770 cifs_stats_inc(&tcon->num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00001771 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001772 cFYI(1, "Send error in Lock = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773
Steve French50c2f752007-07-13 00:33:32 +00001774 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001775 since file handle passed in no longer valid */
1776 return rc;
1777}
1778
1779int
Steve French08547b02006-02-28 22:39:25 +00001780CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1781 const __u16 smb_file_id, const int get_flag, const __u64 len,
Steve French50c2f752007-07-13 00:33:32 +00001782 struct file_lock *pLockData, const __u16 lock_type,
Steve French4b18f2a2008-04-29 00:06:05 +00001783 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00001784{
1785 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1786 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00001787 struct cifs_posix_lock *parm_data;
1788 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00001789 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00001790 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00001791 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00001792 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00001793 struct kvec iov[1];
Steve French08547b02006-02-28 22:39:25 +00001794
Joe Perchesb6b38f72010-04-21 03:50:45 +00001795 cFYI(1, "Posix Lock");
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001796
Steve French790fe572007-07-07 19:25:05 +00001797 if (pLockData == NULL)
Marcin Slusarzed5f0372008-05-13 04:01:01 +00001798 return -EINVAL;
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001799
Steve French08547b02006-02-28 22:39:25 +00001800 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1801
1802 if (rc)
1803 return rc;
1804
1805 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1806
Steve French50c2f752007-07-13 00:33:32 +00001807 params = 6;
Steve French08547b02006-02-28 22:39:25 +00001808 pSMB->MaxSetupCount = 0;
1809 pSMB->Reserved = 0;
1810 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00001811 pSMB->Reserved2 = 0;
1812 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1813 offset = param_offset + params;
1814
Steve French08547b02006-02-28 22:39:25 +00001815 count = sizeof(struct cifs_posix_lock);
1816 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00001817 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00001818 pSMB->SetupCount = 1;
1819 pSMB->Reserved3 = 0;
Steve French790fe572007-07-07 19:25:05 +00001820 if (get_flag)
Steve French08547b02006-02-28 22:39:25 +00001821 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1822 else
1823 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1824 byte_count = 3 /* pad */ + params + count;
1825 pSMB->DataCount = cpu_to_le16(count);
1826 pSMB->ParameterCount = cpu_to_le16(params);
1827 pSMB->TotalDataCount = pSMB->DataCount;
1828 pSMB->TotalParameterCount = pSMB->ParameterCount;
1829 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00001830 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00001831 (((char *) &pSMB->hdr.Protocol) + offset);
1832
1833 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00001834 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00001835 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00001836 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00001837 pSMB->Timeout = cpu_to_le32(-1);
1838 } else
1839 pSMB->Timeout = 0;
1840
Steve French08547b02006-02-28 22:39:25 +00001841 parm_data->pid = cpu_to_le32(current->tgid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001842 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00001843 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00001844
1845 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00001846 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00001847 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1848 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001849 inc_rfc1001_len(pSMB, byte_count);
Steve French08547b02006-02-28 22:39:25 +00001850 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001851 if (waitFlag) {
1852 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1853 (struct smb_hdr *) pSMBr, &bytes_returned);
1854 } else {
Steve French133672e2007-11-13 22:41:37 +00001855 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001856 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French133672e2007-11-13 22:41:37 +00001857 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1858 &resp_buf_type, timeout);
1859 pSMB = NULL; /* request buf already freed by SendReceive2. Do
1860 not try to free it twice below on exit */
1861 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001862 }
1863
Steve French08547b02006-02-28 22:39:25 +00001864 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001865 cFYI(1, "Send error in Posix Lock = %d", rc);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001866 } else if (get_flag) {
1867 /* lock structure can be returned on get */
1868 __u16 data_offset;
1869 __u16 data_count;
1870 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00001871
Jeff Layton820a8032011-05-04 08:05:26 -04001872 if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001873 rc = -EIO; /* bad smb */
1874 goto plk_err_exit;
1875 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001876 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1877 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00001878 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001879 rc = -EIO;
1880 goto plk_err_exit;
1881 }
1882 parm_data = (struct cifs_posix_lock *)
1883 ((char *)&pSMBr->hdr.Protocol + data_offset);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04001884 if (parm_data->lock_type == __constant_cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001885 pLockData->fl_type = F_UNLCK;
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04001886 else {
1887 if (parm_data->lock_type ==
1888 __constant_cpu_to_le16(CIFS_RDLCK))
1889 pLockData->fl_type = F_RDLCK;
1890 else if (parm_data->lock_type ==
1891 __constant_cpu_to_le16(CIFS_WRLCK))
1892 pLockData->fl_type = F_WRLCK;
1893
Steve French5443d132011-03-13 05:08:25 +00001894 pLockData->fl_start = le64_to_cpu(parm_data->start);
1895 pLockData->fl_end = pLockData->fl_start +
1896 le64_to_cpu(parm_data->length) - 1;
1897 pLockData->fl_pid = le32_to_cpu(parm_data->pid);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04001898 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001899 }
Steve French50c2f752007-07-13 00:33:32 +00001900
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001901plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00001902 if (pSMB)
1903 cifs_small_buf_release(pSMB);
1904
Steve French133672e2007-11-13 22:41:37 +00001905 if (resp_buf_type == CIFS_SMALL_BUFFER)
1906 cifs_small_buf_release(iov[0].iov_base);
1907 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1908 cifs_buf_release(iov[0].iov_base);
1909
Steve French08547b02006-02-28 22:39:25 +00001910 /* Note: On -EAGAIN error only caller can retry on handle based calls
1911 since file handle passed in no longer valid */
1912
1913 return rc;
1914}
1915
1916
1917int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1919{
1920 int rc = 0;
1921 CLOSE_REQ *pSMB = NULL;
Joe Perchesb6b38f72010-04-21 03:50:45 +00001922 cFYI(1, "In CIFSSMBClose");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923
1924/* do not retry on dead session on close */
1925 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00001926 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001927 return 0;
1928 if (rc)
1929 return rc;
1930
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00001932 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00001934 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001935 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00001937 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938 /* EINTR is expected when user ctl-c to kill app */
Joe Perchesb6b38f72010-04-21 03:50:45 +00001939 cERROR(1, "Send error in Close = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001940 }
1941 }
1942
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00001944 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945 rc = 0;
1946
1947 return rc;
1948}
1949
1950int
Steve Frenchb298f222009-02-21 21:17:43 +00001951CIFSSMBFlush(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1952{
1953 int rc = 0;
1954 FLUSH_REQ *pSMB = NULL;
Joe Perchesb6b38f72010-04-21 03:50:45 +00001955 cFYI(1, "In CIFSSMBFlush");
Steve Frenchb298f222009-02-21 21:17:43 +00001956
1957 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
1958 if (rc)
1959 return rc;
1960
1961 pSMB->FileID = (__u16) smb_file_id;
1962 pSMB->ByteCount = 0;
1963 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
1964 cifs_stats_inc(&tcon->num_flushes);
1965 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001966 cERROR(1, "Send error in Flush = %d", rc);
Steve Frenchb298f222009-02-21 21:17:43 +00001967
1968 return rc;
1969}
1970
1971int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001972CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1973 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001974 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001975{
1976 int rc = 0;
1977 RENAME_REQ *pSMB = NULL;
1978 RENAME_RSP *pSMBr = NULL;
1979 int bytes_returned;
1980 int name_len, name_len2;
1981 __u16 count;
1982
Joe Perchesb6b38f72010-04-21 03:50:45 +00001983 cFYI(1, "In CIFSSMBRename");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001984renameRetry:
1985 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1986 (void **) &pSMBr);
1987 if (rc)
1988 return rc;
1989
1990 pSMB->BufferFormat = 0x04;
1991 pSMB->SearchAttributes =
1992 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1993 ATTR_DIRECTORY);
1994
1995 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1996 name_len =
Steve French50c2f752007-07-13 00:33:32 +00001997 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001998 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999 name_len++; /* trailing null */
2000 name_len *= 2;
2001 pSMB->OldFileName[name_len] = 0x04; /* pad */
2002 /* protocol requires ASCII signature byte on Unicode string */
2003 pSMB->OldFileName[name_len + 1] = 0x00;
2004 name_len2 =
Steve French582d21e2008-05-13 04:54:12 +00002005 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002006 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002007 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2008 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002009 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010 name_len = strnlen(fromName, PATH_MAX);
2011 name_len++; /* trailing null */
2012 strncpy(pSMB->OldFileName, fromName, name_len);
2013 name_len2 = strnlen(toName, PATH_MAX);
2014 name_len2++; /* trailing null */
2015 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2016 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2017 name_len2++; /* trailing null */
2018 name_len2++; /* signature byte */
2019 }
2020
2021 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002022 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002023 pSMB->ByteCount = cpu_to_le16(count);
2024
2025 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2026 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002027 cifs_stats_inc(&tcon->num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002028 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002029 cFYI(1, "Send error in rename = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002030
Linus Torvalds1da177e2005-04-16 15:20:36 -07002031 cifs_buf_release(pSMB);
2032
2033 if (rc == -EAGAIN)
2034 goto renameRetry;
2035
2036 return rc;
2037}
2038
Steve French50c2f752007-07-13 00:33:32 +00002039int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002040 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002041 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002042{
2043 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2044 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002045 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002046 char *data_offset;
2047 char dummy_string[30];
2048 int rc = 0;
2049 int bytes_returned = 0;
2050 int len_of_str;
2051 __u16 params, param_offset, offset, count, byte_count;
2052
Joe Perchesb6b38f72010-04-21 03:50:45 +00002053 cFYI(1, "Rename to File by handle");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002054 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2055 (void **) &pSMBr);
2056 if (rc)
2057 return rc;
2058
2059 params = 6;
2060 pSMB->MaxSetupCount = 0;
2061 pSMB->Reserved = 0;
2062 pSMB->Flags = 0;
2063 pSMB->Timeout = 0;
2064 pSMB->Reserved2 = 0;
2065 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2066 offset = param_offset + params;
2067
2068 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2069 rename_info = (struct set_file_rename *) data_offset;
2070 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002071 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002072 pSMB->SetupCount = 1;
2073 pSMB->Reserved3 = 0;
2074 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2075 byte_count = 3 /* pad */ + params;
2076 pSMB->ParameterCount = cpu_to_le16(params);
2077 pSMB->TotalParameterCount = pSMB->ParameterCount;
2078 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2079 pSMB->DataOffset = cpu_to_le16(offset);
2080 /* construct random name ".cifs_tmp<inodenum><mid>" */
2081 rename_info->overwrite = cpu_to_le32(1);
2082 rename_info->root_fid = 0;
2083 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002084 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002085 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
2086 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002087 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002088 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05002089 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002090 target_name, PATH_MAX, nls_codepage,
2091 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002092 }
2093 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002094 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002095 byte_count += count;
2096 pSMB->DataCount = cpu_to_le16(count);
2097 pSMB->TotalDataCount = pSMB->DataCount;
2098 pSMB->Fid = netfid;
2099 pSMB->InformationLevel =
2100 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2101 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002102 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002103 pSMB->ByteCount = cpu_to_le16(byte_count);
2104 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002105 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002106 cifs_stats_inc(&pTcon->num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002107 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002108 cFYI(1, "Send error in Rename (by file handle) = %d", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07002109
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110 cifs_buf_release(pSMB);
2111
2112 /* Note: On -EAGAIN error only caller can retry on handle based calls
2113 since file handle passed in no longer valid */
2114
2115 return rc;
2116}
2117
2118int
Steve French50c2f752007-07-13 00:33:32 +00002119CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName,
2120 const __u16 target_tid, const char *toName, const int flags,
2121 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002122{
2123 int rc = 0;
2124 COPY_REQ *pSMB = NULL;
2125 COPY_RSP *pSMBr = NULL;
2126 int bytes_returned;
2127 int name_len, name_len2;
2128 __u16 count;
2129
Joe Perchesb6b38f72010-04-21 03:50:45 +00002130 cFYI(1, "In CIFSSMBCopy");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002131copyRetry:
2132 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2133 (void **) &pSMBr);
2134 if (rc)
2135 return rc;
2136
2137 pSMB->BufferFormat = 0x04;
2138 pSMB->Tid2 = target_tid;
2139
2140 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2141
2142 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00002143 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07002144 fromName, PATH_MAX, nls_codepage,
2145 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002146 name_len++; /* trailing null */
2147 name_len *= 2;
2148 pSMB->OldFileName[name_len] = 0x04; /* pad */
2149 /* protocol requires ASCII signature byte on Unicode string */
2150 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002151 name_len2 =
2152 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002153 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002154 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2155 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002156 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002157 name_len = strnlen(fromName, PATH_MAX);
2158 name_len++; /* trailing null */
2159 strncpy(pSMB->OldFileName, fromName, name_len);
2160 name_len2 = strnlen(toName, PATH_MAX);
2161 name_len2++; /* trailing null */
2162 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2163 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2164 name_len2++; /* trailing null */
2165 name_len2++; /* signature byte */
2166 }
2167
2168 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002169 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002170 pSMB->ByteCount = cpu_to_le16(count);
2171
2172 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2173 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2174 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002175 cFYI(1, "Send error in copy = %d with %d files copied",
2176 rc, le16_to_cpu(pSMBr->CopyCount));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002177 }
Steve French0d817bc2008-05-22 02:02:03 +00002178 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002179
2180 if (rc == -EAGAIN)
2181 goto copyRetry;
2182
2183 return rc;
2184}
2185
2186int
2187CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
2188 const char *fromName, const char *toName,
2189 const struct nls_table *nls_codepage)
2190{
2191 TRANSACTION2_SPI_REQ *pSMB = NULL;
2192 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2193 char *data_offset;
2194 int name_len;
2195 int name_len_target;
2196 int rc = 0;
2197 int bytes_returned = 0;
2198 __u16 params, param_offset, offset, byte_count;
2199
Joe Perchesb6b38f72010-04-21 03:50:45 +00002200 cFYI(1, "In Symlink Unix style");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002201createSymLinkRetry:
2202 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2203 (void **) &pSMBr);
2204 if (rc)
2205 return rc;
2206
2207 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2208 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002209 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002210 /* find define for this maxpathcomponent */
2211 , nls_codepage);
2212 name_len++; /* trailing null */
2213 name_len *= 2;
2214
Steve French50c2f752007-07-13 00:33:32 +00002215 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002216 name_len = strnlen(fromName, PATH_MAX);
2217 name_len++; /* trailing null */
2218 strncpy(pSMB->FileName, fromName, name_len);
2219 }
2220 params = 6 + name_len;
2221 pSMB->MaxSetupCount = 0;
2222 pSMB->Reserved = 0;
2223 pSMB->Flags = 0;
2224 pSMB->Timeout = 0;
2225 pSMB->Reserved2 = 0;
2226 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002227 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002228 offset = param_offset + params;
2229
2230 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2231 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2232 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08002233 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002234 /* find define for this maxpathcomponent */
2235 , nls_codepage);
2236 name_len_target++; /* trailing null */
2237 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002238 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002239 name_len_target = strnlen(toName, PATH_MAX);
2240 name_len_target++; /* trailing null */
2241 strncpy(data_offset, toName, name_len_target);
2242 }
2243
2244 pSMB->MaxParameterCount = cpu_to_le16(2);
2245 /* BB find exact max on data count below from sess */
2246 pSMB->MaxDataCount = cpu_to_le16(1000);
2247 pSMB->SetupCount = 1;
2248 pSMB->Reserved3 = 0;
2249 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2250 byte_count = 3 /* pad */ + params + name_len_target;
2251 pSMB->DataCount = cpu_to_le16(name_len_target);
2252 pSMB->ParameterCount = cpu_to_le16(params);
2253 pSMB->TotalDataCount = pSMB->DataCount;
2254 pSMB->TotalParameterCount = pSMB->ParameterCount;
2255 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2256 pSMB->DataOffset = cpu_to_le16(offset);
2257 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2258 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002259 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002260 pSMB->ByteCount = cpu_to_le16(byte_count);
2261 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2262 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002263 cifs_stats_inc(&tcon->num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002264 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002265 cFYI(1, "Send error in SetPathInfo create symlink = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002266
Steve French0d817bc2008-05-22 02:02:03 +00002267 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002268
2269 if (rc == -EAGAIN)
2270 goto createSymLinkRetry;
2271
2272 return rc;
2273}
2274
2275int
2276CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2277 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002278 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002279{
2280 TRANSACTION2_SPI_REQ *pSMB = NULL;
2281 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2282 char *data_offset;
2283 int name_len;
2284 int name_len_target;
2285 int rc = 0;
2286 int bytes_returned = 0;
2287 __u16 params, param_offset, offset, byte_count;
2288
Joe Perchesb6b38f72010-04-21 03:50:45 +00002289 cFYI(1, "In Create Hard link Unix style");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002290createHardLinkRetry:
2291 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2292 (void **) &pSMBr);
2293 if (rc)
2294 return rc;
2295
2296 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05002297 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07002298 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002299 name_len++; /* trailing null */
2300 name_len *= 2;
2301
Steve French50c2f752007-07-13 00:33:32 +00002302 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002303 name_len = strnlen(toName, PATH_MAX);
2304 name_len++; /* trailing null */
2305 strncpy(pSMB->FileName, toName, name_len);
2306 }
2307 params = 6 + name_len;
2308 pSMB->MaxSetupCount = 0;
2309 pSMB->Reserved = 0;
2310 pSMB->Flags = 0;
2311 pSMB->Timeout = 0;
2312 pSMB->Reserved2 = 0;
2313 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002314 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002315 offset = param_offset + params;
2316
2317 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2318 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2319 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05002320 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07002321 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002322 name_len_target++; /* trailing null */
2323 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002324 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002325 name_len_target = strnlen(fromName, PATH_MAX);
2326 name_len_target++; /* trailing null */
2327 strncpy(data_offset, fromName, name_len_target);
2328 }
2329
2330 pSMB->MaxParameterCount = cpu_to_le16(2);
2331 /* BB find exact max on data count below from sess*/
2332 pSMB->MaxDataCount = cpu_to_le16(1000);
2333 pSMB->SetupCount = 1;
2334 pSMB->Reserved3 = 0;
2335 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2336 byte_count = 3 /* pad */ + params + name_len_target;
2337 pSMB->ParameterCount = cpu_to_le16(params);
2338 pSMB->TotalParameterCount = pSMB->ParameterCount;
2339 pSMB->DataCount = cpu_to_le16(name_len_target);
2340 pSMB->TotalDataCount = pSMB->DataCount;
2341 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2342 pSMB->DataOffset = cpu_to_le16(offset);
2343 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2344 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002345 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002346 pSMB->ByteCount = cpu_to_le16(byte_count);
2347 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2348 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002349 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002350 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002351 cFYI(1, "Send error in SetPathInfo (hard link) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002352
2353 cifs_buf_release(pSMB);
2354 if (rc == -EAGAIN)
2355 goto createHardLinkRetry;
2356
2357 return rc;
2358}
2359
2360int
2361CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2362 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002363 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002364{
2365 int rc = 0;
2366 NT_RENAME_REQ *pSMB = NULL;
2367 RENAME_RSP *pSMBr = NULL;
2368 int bytes_returned;
2369 int name_len, name_len2;
2370 __u16 count;
2371
Joe Perchesb6b38f72010-04-21 03:50:45 +00002372 cFYI(1, "In CIFSCreateHardLink");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002373winCreateHardLinkRetry:
2374
2375 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2376 (void **) &pSMBr);
2377 if (rc)
2378 return rc;
2379
2380 pSMB->SearchAttributes =
2381 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2382 ATTR_DIRECTORY);
2383 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2384 pSMB->ClusterCount = 0;
2385
2386 pSMB->BufferFormat = 0x04;
2387
2388 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2389 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002390 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002391 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002392 name_len++; /* trailing null */
2393 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05002394
2395 /* protocol specifies ASCII buffer format (0x04) for unicode */
2396 pSMB->OldFileName[name_len] = 0x04;
2397 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002398 name_len2 =
Steve French50c2f752007-07-13 00:33:32 +00002399 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002400 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002401 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2402 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002403 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002404 name_len = strnlen(fromName, PATH_MAX);
2405 name_len++; /* trailing null */
2406 strncpy(pSMB->OldFileName, fromName, name_len);
2407 name_len2 = strnlen(toName, PATH_MAX);
2408 name_len2++; /* trailing null */
2409 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2410 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2411 name_len2++; /* trailing null */
2412 name_len2++; /* signature byte */
2413 }
2414
2415 count = 1 /* string type byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002416 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002417 pSMB->ByteCount = cpu_to_le16(count);
2418
2419 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2420 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002421 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002422 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002423 cFYI(1, "Send error in hard link (NT rename) = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00002424
Linus Torvalds1da177e2005-04-16 15:20:36 -07002425 cifs_buf_release(pSMB);
2426 if (rc == -EAGAIN)
2427 goto winCreateHardLinkRetry;
2428
2429 return rc;
2430}
2431
2432int
2433CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04002434 const unsigned char *searchName, char **symlinkinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002435 const struct nls_table *nls_codepage)
2436{
2437/* SMB_QUERY_FILE_UNIX_LINK */
2438 TRANSACTION2_QPI_REQ *pSMB = NULL;
2439 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2440 int rc = 0;
2441 int bytes_returned;
2442 int name_len;
2443 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04002444 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002445
Joe Perchesb6b38f72010-04-21 03:50:45 +00002446 cFYI(1, "In QPathSymLinkInfo (Unix) for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002447
2448querySymLinkRetry:
2449 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2450 (void **) &pSMBr);
2451 if (rc)
2452 return rc;
2453
2454 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2455 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002456 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
2457 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002458 name_len++; /* trailing null */
2459 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002460 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002461 name_len = strnlen(searchName, PATH_MAX);
2462 name_len++; /* trailing null */
2463 strncpy(pSMB->FileName, searchName, name_len);
2464 }
2465
2466 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2467 pSMB->TotalDataCount = 0;
2468 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04002469 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002470 pSMB->MaxSetupCount = 0;
2471 pSMB->Reserved = 0;
2472 pSMB->Flags = 0;
2473 pSMB->Timeout = 0;
2474 pSMB->Reserved2 = 0;
2475 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00002476 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002477 pSMB->DataCount = 0;
2478 pSMB->DataOffset = 0;
2479 pSMB->SetupCount = 1;
2480 pSMB->Reserved3 = 0;
2481 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2482 byte_count = params + 1 /* pad */ ;
2483 pSMB->TotalParameterCount = cpu_to_le16(params);
2484 pSMB->ParameterCount = pSMB->TotalParameterCount;
2485 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2486 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002487 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002488 pSMB->ByteCount = cpu_to_le16(byte_count);
2489
2490 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2491 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2492 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002493 cFYI(1, "Send error in QuerySymLinkInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002494 } else {
2495 /* decode response */
2496
2497 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002498 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04002499 if (rc || get_bcc(&pSMBr->hdr) < 2)
Jeff Layton460b9692009-04-30 07:17:56 -04002500 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002501 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00002502 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04002503 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002504
Jeff Layton460b9692009-04-30 07:17:56 -04002505 data_start = ((char *) &pSMBr->hdr.Protocol) +
2506 le16_to_cpu(pSMBr->t2.DataOffset);
2507
Steve French0e0d2cf2009-05-01 05:27:32 +00002508 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2509 is_unicode = true;
2510 else
2511 is_unicode = false;
2512
Steve French737b7582005-04-28 22:41:06 -07002513 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchd185cda2009-04-30 17:45:10 +00002514 *symlinkinfo = cifs_strndup_from_ucs(data_start, count,
Steve French0e0d2cf2009-05-01 05:27:32 +00002515 is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04002516 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04002517 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002518 }
2519 }
2520 cifs_buf_release(pSMB);
2521 if (rc == -EAGAIN)
2522 goto querySymLinkRetry;
2523 return rc;
2524}
2525
Steve Frenchc52a95542011-02-24 06:16:22 +00002526#ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL
2527/*
2528 * Recent Windows versions now create symlinks more frequently
2529 * and they use the "reparse point" mechanism below. We can of course
2530 * do symlinks nicely to Samba and other servers which support the
2531 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
2532 * "MF" symlinks optionally, but for recent Windows we really need to
2533 * reenable the code below and fix the cifs_symlink callers to handle this.
2534 * In the interim this code has been moved to its own config option so
2535 * it is not compiled in by default until callers fixed up and more tested.
2536 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002537int
2538CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2539 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00002540 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002541 const struct nls_table *nls_codepage)
2542{
2543 int rc = 0;
2544 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00002545 struct smb_com_transaction_ioctl_req *pSMB;
2546 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002547
Joe Perchesb6b38f72010-04-21 03:50:45 +00002548 cFYI(1, "In Windows reparse style QueryLink for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002549 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2550 (void **) &pSMBr);
2551 if (rc)
2552 return rc;
2553
2554 pSMB->TotalParameterCount = 0 ;
2555 pSMB->TotalDataCount = 0;
2556 pSMB->MaxParameterCount = cpu_to_le32(2);
2557 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002558 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2559 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002560 pSMB->MaxSetupCount = 4;
2561 pSMB->Reserved = 0;
2562 pSMB->ParameterOffset = 0;
2563 pSMB->DataCount = 0;
2564 pSMB->DataOffset = 0;
2565 pSMB->SetupCount = 4;
2566 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2567 pSMB->ParameterCount = pSMB->TotalParameterCount;
2568 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2569 pSMB->IsFsctl = 1; /* FSCTL */
2570 pSMB->IsRootFlag = 0;
2571 pSMB->Fid = fid; /* file handle always le */
2572 pSMB->ByteCount = 0;
2573
2574 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2575 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2576 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002577 cFYI(1, "Send error in QueryReparseLinkInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002578 } else { /* decode response */
2579 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2580 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
Jeff Layton820a8032011-05-04 08:05:26 -04002581 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
2582 /* BB also check enough total bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002583 rc = -EIO; /* bad smb */
Steve Frenchafe48c32009-05-02 05:25:46 +00002584 goto qreparse_out;
2585 }
2586 if (data_count && (data_count < 2048)) {
2587 char *end_of_smb = 2 /* sizeof byte count */ +
Jeff Layton820a8032011-05-04 08:05:26 -04002588 get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002589
Steve Frenchafe48c32009-05-02 05:25:46 +00002590 struct reparse_data *reparse_buf =
Steve French50c2f752007-07-13 00:33:32 +00002591 (struct reparse_data *)
2592 ((char *)&pSMBr->hdr.Protocol
2593 + data_offset);
Steve Frenchafe48c32009-05-02 05:25:46 +00002594 if ((char *)reparse_buf >= end_of_smb) {
2595 rc = -EIO;
2596 goto qreparse_out;
2597 }
2598 if ((reparse_buf->LinkNamesBuf +
2599 reparse_buf->TargetNameOffset +
2600 reparse_buf->TargetNameLen) > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002601 cFYI(1, "reparse buf beyond SMB");
Steve Frenchafe48c32009-05-02 05:25:46 +00002602 rc = -EIO;
2603 goto qreparse_out;
2604 }
Steve French50c2f752007-07-13 00:33:32 +00002605
Steve Frenchafe48c32009-05-02 05:25:46 +00002606 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2607 cifs_from_ucs2(symlinkinfo, (__le16 *)
Steve French50c2f752007-07-13 00:33:32 +00002608 (reparse_buf->LinkNamesBuf +
2609 reparse_buf->TargetNameOffset),
Steve Frenchafe48c32009-05-02 05:25:46 +00002610 buflen,
2611 reparse_buf->TargetNameLen,
2612 nls_codepage, 0);
2613 } else { /* ASCII names */
2614 strncpy(symlinkinfo,
2615 reparse_buf->LinkNamesBuf +
2616 reparse_buf->TargetNameOffset,
2617 min_t(const int, buflen,
2618 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002619 }
Steve Frenchafe48c32009-05-02 05:25:46 +00002620 } else {
2621 rc = -EIO;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002622 cFYI(1, "Invalid return data count on "
2623 "get reparse info ioctl");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002624 }
Steve Frenchafe48c32009-05-02 05:25:46 +00002625 symlinkinfo[buflen] = 0; /* just in case so the caller
2626 does not go off the end of the buffer */
Joe Perchesb6b38f72010-04-21 03:50:45 +00002627 cFYI(1, "readlink result - %s", symlinkinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002628 }
Steve French989c7e52009-05-02 05:32:20 +00002629
Linus Torvalds1da177e2005-04-16 15:20:36 -07002630qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002631 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002632
2633 /* Note: On -EAGAIN error only caller can retry on handle based calls
2634 since file handle passed in no longer valid */
2635
2636 return rc;
2637}
Steve Frenchc52a95542011-02-24 06:16:22 +00002638#endif /* CIFS_SYMLINK_EXPERIMENTAL */ /* BB temporarily unused */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002639
2640#ifdef CONFIG_CIFS_POSIX
2641
2642/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00002643static void cifs_convert_ace(posix_acl_xattr_entry *ace,
2644 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002645{
2646 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002647 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2648 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2649 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesb6b38f72010-04-21 03:50:45 +00002650 /* cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651
2652 return;
2653}
2654
2655/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00002656static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
2657 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002658{
2659 int size = 0;
2660 int i;
2661 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00002662 struct cifs_posix_ace *pACE;
2663 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
2664 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002665
2666 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2667 return -EOPNOTSUPP;
2668
Steve French790fe572007-07-07 19:25:05 +00002669 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002670 count = le16_to_cpu(cifs_acl->access_entry_count);
2671 pACE = &cifs_acl->ace_array[0];
2672 size = sizeof(struct cifs_posix_acl);
2673 size += sizeof(struct cifs_posix_ace) * count;
2674 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002675 if (size_of_data_area < size) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002676 cFYI(1, "bad CIFS POSIX ACL size %d vs. %d",
2677 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002678 return -EINVAL;
2679 }
Steve French790fe572007-07-07 19:25:05 +00002680 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002681 count = le16_to_cpu(cifs_acl->access_entry_count);
2682 size = sizeof(struct cifs_posix_acl);
2683 size += sizeof(struct cifs_posix_ace) * count;
2684/* skip past access ACEs to get to default ACEs */
2685 pACE = &cifs_acl->ace_array[count];
2686 count = le16_to_cpu(cifs_acl->default_entry_count);
2687 size += sizeof(struct cifs_posix_ace) * count;
2688 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002689 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002690 return -EINVAL;
2691 } else {
2692 /* illegal type */
2693 return -EINVAL;
2694 }
2695
2696 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00002697 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00002698 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00002699 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002700 return -ERANGE;
2701 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002702 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00002703 for (i = 0; i < count ; i++) {
2704 cifs_convert_ace(&local_acl->a_entries[i], pACE);
2705 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002706 }
2707 }
2708 return size;
2709}
2710
Steve French50c2f752007-07-13 00:33:32 +00002711static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
2712 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002713{
2714 __u16 rc = 0; /* 0 = ACL converted ok */
2715
Steve Frenchff7feac2005-11-15 16:45:16 -08002716 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2717 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002718 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00002719 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002720 /* Probably no need to le convert -1 on any arch but can not hurt */
2721 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00002722 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002723 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesb6b38f72010-04-21 03:50:45 +00002724 /*cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id);*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002725 return rc;
2726}
2727
2728/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00002729static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
2730 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002731{
2732 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00002733 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
2734 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735 int count;
2736 int i;
2737
Steve French790fe572007-07-07 19:25:05 +00002738 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002739 return 0;
2740
2741 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesb6b38f72010-04-21 03:50:45 +00002742 cFYI(1, "setting acl with %d entries from buf of length %d and "
Steve French63135e02007-07-17 17:34:02 +00002743 "version of %d",
Joe Perchesb6b38f72010-04-21 03:50:45 +00002744 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00002745 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002746 cFYI(1, "unknown POSIX ACL version %d",
2747 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748 return 0;
2749 }
2750 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00002751 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08002752 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00002753 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08002754 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002755 else {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002756 cFYI(1, "unknown ACL type %d", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002757 return 0;
2758 }
Steve French50c2f752007-07-13 00:33:32 +00002759 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002760 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2761 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00002762 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002763 /* ACE not converted */
2764 break;
2765 }
2766 }
Steve French790fe572007-07-07 19:25:05 +00002767 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002768 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2769 rc += sizeof(struct cifs_posix_acl);
2770 /* BB add check to make sure ACL does not overflow SMB */
2771 }
2772 return rc;
2773}
2774
2775int
2776CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002777 const unsigned char *searchName,
2778 char *acl_inf, const int buflen, const int acl_type,
2779 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002780{
2781/* SMB_QUERY_POSIX_ACL */
2782 TRANSACTION2_QPI_REQ *pSMB = NULL;
2783 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2784 int rc = 0;
2785 int bytes_returned;
2786 int name_len;
2787 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00002788
Joe Perchesb6b38f72010-04-21 03:50:45 +00002789 cFYI(1, "In GetPosixACL (Unix) for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002790
2791queryAclRetry:
2792 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2793 (void **) &pSMBr);
2794 if (rc)
2795 return rc;
Steve French50c2f752007-07-13 00:33:32 +00002796
Linus Torvalds1da177e2005-04-16 15:20:36 -07002797 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2798 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002799 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002800 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002801 name_len++; /* trailing null */
2802 name_len *= 2;
2803 pSMB->FileName[name_len] = 0;
2804 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00002805 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002806 name_len = strnlen(searchName, PATH_MAX);
2807 name_len++; /* trailing null */
2808 strncpy(pSMB->FileName, searchName, name_len);
2809 }
2810
2811 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2812 pSMB->TotalDataCount = 0;
2813 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00002814 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002815 pSMB->MaxDataCount = cpu_to_le16(4000);
2816 pSMB->MaxSetupCount = 0;
2817 pSMB->Reserved = 0;
2818 pSMB->Flags = 0;
2819 pSMB->Timeout = 0;
2820 pSMB->Reserved2 = 0;
2821 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00002822 offsetof(struct smb_com_transaction2_qpi_req,
2823 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002824 pSMB->DataCount = 0;
2825 pSMB->DataOffset = 0;
2826 pSMB->SetupCount = 1;
2827 pSMB->Reserved3 = 0;
2828 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2829 byte_count = params + 1 /* pad */ ;
2830 pSMB->TotalParameterCount = cpu_to_le16(params);
2831 pSMB->ParameterCount = pSMB->TotalParameterCount;
2832 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2833 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002834 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002835 pSMB->ByteCount = cpu_to_le16(byte_count);
2836
2837 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2838 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08002839 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002840 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002841 cFYI(1, "Send error in Query POSIX ACL = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002842 } else {
2843 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00002844
Linus Torvalds1da177e2005-04-16 15:20:36 -07002845 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002846 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04002847 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002848 rc = -EIO; /* bad smb */
2849 else {
2850 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2851 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2852 rc = cifs_copy_posix_acl(acl_inf,
2853 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00002854 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002855 }
2856 }
2857 cifs_buf_release(pSMB);
2858 if (rc == -EAGAIN)
2859 goto queryAclRetry;
2860 return rc;
2861}
2862
2863int
2864CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002865 const unsigned char *fileName,
2866 const char *local_acl, const int buflen,
2867 const int acl_type,
2868 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002869{
2870 struct smb_com_transaction2_spi_req *pSMB = NULL;
2871 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2872 char *parm_data;
2873 int name_len;
2874 int rc = 0;
2875 int bytes_returned = 0;
2876 __u16 params, byte_count, data_count, param_offset, offset;
2877
Joe Perchesb6b38f72010-04-21 03:50:45 +00002878 cFYI(1, "In SetPosixACL (Unix) for path %s", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002879setAclRetry:
2880 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002881 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002882 if (rc)
2883 return rc;
2884 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2885 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002886 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002887 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002888 name_len++; /* trailing null */
2889 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002890 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002891 name_len = strnlen(fileName, PATH_MAX);
2892 name_len++; /* trailing null */
2893 strncpy(pSMB->FileName, fileName, name_len);
2894 }
2895 params = 6 + name_len;
2896 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00002897 /* BB find max SMB size from sess */
2898 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002899 pSMB->MaxSetupCount = 0;
2900 pSMB->Reserved = 0;
2901 pSMB->Flags = 0;
2902 pSMB->Timeout = 0;
2903 pSMB->Reserved2 = 0;
2904 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002905 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002906 offset = param_offset + params;
2907 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2908 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2909
2910 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00002911 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002912
Steve French790fe572007-07-07 19:25:05 +00002913 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002914 rc = -EOPNOTSUPP;
2915 goto setACLerrorExit;
2916 }
2917 pSMB->DataOffset = cpu_to_le16(offset);
2918 pSMB->SetupCount = 1;
2919 pSMB->Reserved3 = 0;
2920 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2921 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2922 byte_count = 3 /* pad */ + params + data_count;
2923 pSMB->DataCount = cpu_to_le16(data_count);
2924 pSMB->TotalDataCount = pSMB->DataCount;
2925 pSMB->ParameterCount = cpu_to_le16(params);
2926 pSMB->TotalParameterCount = pSMB->ParameterCount;
2927 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002928 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002929 pSMB->ByteCount = cpu_to_le16(byte_count);
2930 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002931 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00002932 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002933 cFYI(1, "Set POSIX ACL returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002934
2935setACLerrorExit:
2936 cifs_buf_release(pSMB);
2937 if (rc == -EAGAIN)
2938 goto setAclRetry;
2939 return rc;
2940}
2941
Steve Frenchf654bac2005-04-28 22:41:04 -07002942/* BB fix tabs in this function FIXME BB */
2943int
2944CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00002945 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07002946{
Steve French50c2f752007-07-13 00:33:32 +00002947 int rc = 0;
2948 struct smb_t2_qfi_req *pSMB = NULL;
2949 struct smb_t2_qfi_rsp *pSMBr = NULL;
2950 int bytes_returned;
2951 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07002952
Joe Perchesb6b38f72010-04-21 03:50:45 +00002953 cFYI(1, "In GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00002954 if (tcon == NULL)
2955 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07002956
2957GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00002958 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2959 (void **) &pSMBr);
2960 if (rc)
2961 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07002962
Steve Frenchad7a2922008-02-07 23:25:02 +00002963 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00002964 pSMB->t2.TotalDataCount = 0;
2965 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
2966 /* BB find exact max data count below from sess structure BB */
2967 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2968 pSMB->t2.MaxSetupCount = 0;
2969 pSMB->t2.Reserved = 0;
2970 pSMB->t2.Flags = 0;
2971 pSMB->t2.Timeout = 0;
2972 pSMB->t2.Reserved2 = 0;
2973 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2974 Fid) - 4);
2975 pSMB->t2.DataCount = 0;
2976 pSMB->t2.DataOffset = 0;
2977 pSMB->t2.SetupCount = 1;
2978 pSMB->t2.Reserved3 = 0;
2979 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2980 byte_count = params + 1 /* pad */ ;
2981 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2982 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2983 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
2984 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07002985 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002986 inc_rfc1001_len(pSMB, byte_count);
Steve French790fe572007-07-07 19:25:05 +00002987 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07002988
Steve French790fe572007-07-07 19:25:05 +00002989 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2990 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2991 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002992 cFYI(1, "error %d in GetExtAttr", rc);
Steve French790fe572007-07-07 19:25:05 +00002993 } else {
2994 /* decode response */
2995 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00002996 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04002997 if (rc || get_bcc(&pSMBr->hdr) < 2)
Steve French790fe572007-07-07 19:25:05 +00002998 /* If rc should we check for EOPNOSUPP and
2999 disable the srvino flag? or in caller? */
3000 rc = -EIO; /* bad smb */
3001 else {
3002 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3003 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3004 struct file_chattr_info *pfinfo;
3005 /* BB Do we need a cast or hash here ? */
3006 if (count != 16) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003007 cFYI(1, "Illegal size ret in GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00003008 rc = -EIO;
3009 goto GetExtAttrOut;
3010 }
3011 pfinfo = (struct file_chattr_info *)
3012 (data_offset + (char *) &pSMBr->hdr.Protocol);
3013 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003014 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003015 }
3016 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003017GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003018 cifs_buf_release(pSMB);
3019 if (rc == -EAGAIN)
3020 goto GetExtAttrRetry;
3021 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003022}
3023
Steve Frenchf654bac2005-04-28 22:41:04 -07003024#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003025
Jeff Layton79df1ba2010-12-06 12:52:08 -05003026#ifdef CONFIG_CIFS_ACL
3027/*
3028 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3029 * all NT TRANSACTS that we init here have total parm and data under about 400
3030 * bytes (to fit in small cifs buffer size), which is the case so far, it
3031 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3032 * returned setup area) and MaxParameterCount (returned parms size) must be set
3033 * by caller
3034 */
3035static int
3036smb_init_nttransact(const __u16 sub_command, const int setup_count,
3037 const int parm_len, struct cifsTconInfo *tcon,
3038 void **ret_buf)
3039{
3040 int rc;
3041 __u32 temp_offset;
3042 struct smb_com_ntransact_req *pSMB;
3043
3044 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3045 (void **)&pSMB);
3046 if (rc)
3047 return rc;
3048 *ret_buf = (void *)pSMB;
3049 pSMB->Reserved = 0;
3050 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3051 pSMB->TotalDataCount = 0;
3052 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
3053 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3054 pSMB->ParameterCount = pSMB->TotalParameterCount;
3055 pSMB->DataCount = pSMB->TotalDataCount;
3056 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3057 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3058 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3059 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3060 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3061 pSMB->SubCommand = cpu_to_le16(sub_command);
3062 return 0;
3063}
3064
3065static int
3066validate_ntransact(char *buf, char **ppparm, char **ppdata,
3067 __u32 *pparmlen, __u32 *pdatalen)
3068{
3069 char *end_of_smb;
3070 __u32 data_count, data_offset, parm_count, parm_offset;
3071 struct smb_com_ntransact_rsp *pSMBr;
Jeff Layton820a8032011-05-04 08:05:26 -04003072 u16 bcc;
Jeff Layton79df1ba2010-12-06 12:52:08 -05003073
3074 *pdatalen = 0;
3075 *pparmlen = 0;
3076
3077 if (buf == NULL)
3078 return -EINVAL;
3079
3080 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3081
Jeff Layton820a8032011-05-04 08:05:26 -04003082 bcc = get_bcc(&pSMBr->hdr);
3083 end_of_smb = 2 /* sizeof byte count */ + bcc +
Jeff Layton79df1ba2010-12-06 12:52:08 -05003084 (char *)&pSMBr->ByteCount;
3085
3086 data_offset = le32_to_cpu(pSMBr->DataOffset);
3087 data_count = le32_to_cpu(pSMBr->DataCount);
3088 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3089 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3090
3091 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3092 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3093
3094 /* should we also check that parm and data areas do not overlap? */
3095 if (*ppparm > end_of_smb) {
3096 cFYI(1, "parms start after end of smb");
3097 return -EINVAL;
3098 } else if (parm_count + *ppparm > end_of_smb) {
3099 cFYI(1, "parm end after end of smb");
3100 return -EINVAL;
3101 } else if (*ppdata > end_of_smb) {
3102 cFYI(1, "data starts after end of smb");
3103 return -EINVAL;
3104 } else if (data_count + *ppdata > end_of_smb) {
3105 cFYI(1, "data %p + count %d (%p) past smb end %p start %p",
3106 *ppdata, data_count, (data_count + *ppdata),
3107 end_of_smb, pSMBr);
3108 return -EINVAL;
Jeff Layton820a8032011-05-04 08:05:26 -04003109 } else if (parm_count + data_count > bcc) {
Jeff Layton79df1ba2010-12-06 12:52:08 -05003110 cFYI(1, "parm count and data count larger than SMB");
3111 return -EINVAL;
3112 }
3113 *pdatalen = data_count;
3114 *pparmlen = parm_count;
3115 return 0;
3116}
3117
Steve French0a4b92c2006-01-12 15:44:21 -08003118/* Get Security Descriptor (by handle) from remote server for a file or dir */
3119int
3120CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003121 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003122{
3123 int rc = 0;
3124 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003125 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003126 struct kvec iov[1];
3127
Joe Perchesb6b38f72010-04-21 03:50:45 +00003128 cFYI(1, "GetCifsACL");
Steve French0a4b92c2006-01-12 15:44:21 -08003129
Steve French630f3f0c2007-10-25 21:17:17 +00003130 *pbuflen = 0;
3131 *acl_inf = NULL;
3132
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003133 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003134 8 /* parm len */, tcon, (void **) &pSMB);
3135 if (rc)
3136 return rc;
3137
3138 pSMB->MaxParameterCount = cpu_to_le32(4);
3139 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3140 pSMB->MaxSetupCount = 0;
3141 pSMB->Fid = fid; /* file handle always le */
3142 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3143 CIFS_ACL_DACL);
3144 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003145 inc_rfc1001_len(pSMB, 11);
Steve French0a4b92c2006-01-12 15:44:21 -08003146 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003147 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French0a4b92c2006-01-12 15:44:21 -08003148
Steve Frencha761ac52007-10-18 21:45:27 +00003149 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Jeff Layton77499812011-01-11 07:24:23 -05003150 0);
Steve French0a4b92c2006-01-12 15:44:21 -08003151 cifs_stats_inc(&tcon->num_acl_get);
3152 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003153 cFYI(1, "Send error in QuerySecDesc = %d", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08003154 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003155 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003156 __u32 parm_len;
3157 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003158 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003159 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003160
3161/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003162 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003163 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003164 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003165 goto qsec_out;
3166 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3167
Joe Perchesb6b38f72010-04-21 03:50:45 +00003168 cFYI(1, "smb %p parm %p data %p", pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08003169
3170 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3171 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003172 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003173 goto qsec_out;
3174 }
3175
3176/* BB check that data area is minimum length and as big as acl_len */
3177
Steve Frenchaf6f4612007-10-16 18:40:37 +00003178 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003179 if (acl_len != *pbuflen) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003180 cERROR(1, "acl length %d does not match %d",
3181 acl_len, *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003182 if (*pbuflen > acl_len)
3183 *pbuflen = acl_len;
3184 }
Steve French0a4b92c2006-01-12 15:44:21 -08003185
Steve French630f3f0c2007-10-25 21:17:17 +00003186 /* check if buffer is big enough for the acl
3187 header followed by the smallest SID */
3188 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3189 (*pbuflen >= 64 * 1024)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003190 cERROR(1, "bad acl length %d", *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003191 rc = -EINVAL;
3192 *pbuflen = 0;
3193 } else {
3194 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3195 if (*acl_inf == NULL) {
3196 *pbuflen = 0;
3197 rc = -ENOMEM;
3198 }
3199 memcpy(*acl_inf, pdata, *pbuflen);
3200 }
Steve French0a4b92c2006-01-12 15:44:21 -08003201 }
3202qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003203 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003204 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003205 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003206 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003207/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003208 return rc;
3209}
Steve French97837582007-12-31 07:47:21 +00003210
3211int
3212CIFSSMBSetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3213 struct cifs_ntsd *pntsd, __u32 acllen)
3214{
3215 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3216 int rc = 0;
3217 int bytes_returned = 0;
3218 SET_SEC_DESC_REQ *pSMB = NULL;
3219 NTRANSACT_RSP *pSMBr = NULL;
3220
3221setCifsAclRetry:
3222 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB,
3223 (void **) &pSMBr);
3224 if (rc)
3225 return (rc);
3226
3227 pSMB->MaxSetupCount = 0;
3228 pSMB->Reserved = 0;
3229
3230 param_count = 8;
3231 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3232 data_count = acllen;
3233 data_offset = param_offset + param_count;
3234 byte_count = 3 /* pad */ + param_count;
3235
3236 pSMB->DataCount = cpu_to_le32(data_count);
3237 pSMB->TotalDataCount = pSMB->DataCount;
3238 pSMB->MaxParameterCount = cpu_to_le32(4);
3239 pSMB->MaxDataCount = cpu_to_le32(16384);
3240 pSMB->ParameterCount = cpu_to_le32(param_count);
3241 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3242 pSMB->TotalParameterCount = pSMB->ParameterCount;
3243 pSMB->DataOffset = cpu_to_le32(data_offset);
3244 pSMB->SetupCount = 0;
3245 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3246 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3247
3248 pSMB->Fid = fid; /* file handle always le */
3249 pSMB->Reserved2 = 0;
3250 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_DACL);
3251
3252 if (pntsd && acllen) {
3253 memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
3254 (char *) pntsd,
3255 acllen);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003256 inc_rfc1001_len(pSMB, byte_count + data_count);
Steve French97837582007-12-31 07:47:21 +00003257 } else
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003258 inc_rfc1001_len(pSMB, byte_count);
Steve French97837582007-12-31 07:47:21 +00003259
3260 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3261 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3262
Joe Perchesb6b38f72010-04-21 03:50:45 +00003263 cFYI(1, "SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00003264 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003265 cFYI(1, "Set CIFS ACL returned %d", rc);
Steve French97837582007-12-31 07:47:21 +00003266 cifs_buf_release(pSMB);
3267
3268 if (rc == -EAGAIN)
3269 goto setCifsAclRetry;
3270
3271 return (rc);
3272}
3273
Jeff Layton79df1ba2010-12-06 12:52:08 -05003274#endif /* CONFIG_CIFS_ACL */
Steve French0a4b92c2006-01-12 15:44:21 -08003275
Steve French6b8edfe2005-08-23 20:26:03 -07003276/* Legacy Query Path Information call for lookup to old servers such
3277 as Win9x/WinME */
3278int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003279 const unsigned char *searchName,
3280 FILE_ALL_INFO *pFinfo,
3281 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003282{
Steve Frenchad7a2922008-02-07 23:25:02 +00003283 QUERY_INFORMATION_REQ *pSMB;
3284 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003285 int rc = 0;
3286 int bytes_returned;
3287 int name_len;
3288
Joe Perchesb6b38f72010-04-21 03:50:45 +00003289 cFYI(1, "In SMBQPath path %s", searchName);
Steve French6b8edfe2005-08-23 20:26:03 -07003290QInfRetry:
3291 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003292 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003293 if (rc)
3294 return rc;
3295
3296 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3297 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003298 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3299 PATH_MAX, nls_codepage, remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003300 name_len++; /* trailing null */
3301 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003302 } else {
Steve French6b8edfe2005-08-23 20:26:03 -07003303 name_len = strnlen(searchName, PATH_MAX);
3304 name_len++; /* trailing null */
3305 strncpy(pSMB->FileName, searchName, name_len);
3306 }
3307 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003308 name_len++; /* account for buffer type byte */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003309 inc_rfc1001_len(pSMB, (__u16)name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07003310 pSMB->ByteCount = cpu_to_le16(name_len);
3311
3312 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003313 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003314 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003315 cFYI(1, "Send error in QueryInfo = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00003316 } else if (pFinfo) {
Steve French1bd5bbc2006-09-28 03:35:57 +00003317 struct timespec ts;
3318 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00003319
3320 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003321 /* BB FIXME - add time zone adjustment BB */
Steve French6b8edfe2005-08-23 20:26:03 -07003322 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003323 ts.tv_nsec = 0;
3324 ts.tv_sec = time;
3325 /* decode time fields */
Al Viro733f99a2006-10-14 16:48:26 +01003326 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
Steve French1bd5bbc2006-09-28 03:35:57 +00003327 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3328 pFinfo->LastAccessTime = 0;
Steve French70ca7342005-09-22 16:32:06 -07003329 pFinfo->AllocationSize =
3330 cpu_to_le64(le32_to_cpu(pSMBr->size));
3331 pFinfo->EndOfFile = pFinfo->AllocationSize;
3332 pFinfo->Attributes =
3333 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003334 } else
3335 rc = -EIO; /* bad buffer passed in */
3336
3337 cifs_buf_release(pSMB);
3338
3339 if (rc == -EAGAIN)
3340 goto QInfRetry;
3341
3342 return rc;
3343}
3344
Jeff Laytonbcd53572010-02-12 07:44:16 -05003345int
3346CIFSSMBQFileInfo(const int xid, struct cifsTconInfo *tcon,
3347 u16 netfid, FILE_ALL_INFO *pFindData)
3348{
3349 struct smb_t2_qfi_req *pSMB = NULL;
3350 struct smb_t2_qfi_rsp *pSMBr = NULL;
3351 int rc = 0;
3352 int bytes_returned;
3353 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07003354
Jeff Laytonbcd53572010-02-12 07:44:16 -05003355QFileInfoRetry:
3356 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3357 (void **) &pSMBr);
3358 if (rc)
3359 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07003360
Jeff Laytonbcd53572010-02-12 07:44:16 -05003361 params = 2 /* level */ + 2 /* fid */;
3362 pSMB->t2.TotalDataCount = 0;
3363 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3364 /* BB find exact max data count below from sess structure BB */
3365 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3366 pSMB->t2.MaxSetupCount = 0;
3367 pSMB->t2.Reserved = 0;
3368 pSMB->t2.Flags = 0;
3369 pSMB->t2.Timeout = 0;
3370 pSMB->t2.Reserved2 = 0;
3371 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3372 Fid) - 4);
3373 pSMB->t2.DataCount = 0;
3374 pSMB->t2.DataOffset = 0;
3375 pSMB->t2.SetupCount = 1;
3376 pSMB->t2.Reserved3 = 0;
3377 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3378 byte_count = params + 1 /* pad */ ;
3379 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3380 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3381 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3382 pSMB->Pad = 0;
3383 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003384 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003385
3386 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3387 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3388 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00003389 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003390 } else { /* decode response */
3391 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3392
3393 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3394 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04003395 else if (get_bcc(&pSMBr->hdr) < 40)
Jeff Laytonbcd53572010-02-12 07:44:16 -05003396 rc = -EIO; /* bad smb */
3397 else if (pFindData) {
3398 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3399 memcpy((char *) pFindData,
3400 (char *) &pSMBr->hdr.Protocol +
3401 data_offset, sizeof(FILE_ALL_INFO));
3402 } else
3403 rc = -ENOMEM;
3404 }
3405 cifs_buf_release(pSMB);
3406 if (rc == -EAGAIN)
3407 goto QFileInfoRetry;
3408
3409 return rc;
3410}
Steve French6b8edfe2005-08-23 20:26:03 -07003411
Linus Torvalds1da177e2005-04-16 15:20:36 -07003412int
3413CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3414 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003415 FILE_ALL_INFO *pFindData,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003416 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003417 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003418{
3419/* level 263 SMB_QUERY_FILE_ALL_INFO */
3420 TRANSACTION2_QPI_REQ *pSMB = NULL;
3421 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3422 int rc = 0;
3423 int bytes_returned;
3424 int name_len;
3425 __u16 params, byte_count;
3426
Joe Perchesb6b38f72010-04-21 03:50:45 +00003427/* cFYI(1, "In QPathInfo path %s", searchName); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003428QPathInfoRetry:
3429 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3430 (void **) &pSMBr);
3431 if (rc)
3432 return rc;
3433
3434 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3435 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003436 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003437 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003438 name_len++; /* trailing null */
3439 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003440 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003441 name_len = strnlen(searchName, PATH_MAX);
3442 name_len++; /* trailing null */
3443 strncpy(pSMB->FileName, searchName, name_len);
3444 }
3445
Steve French50c2f752007-07-13 00:33:32 +00003446 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003447 pSMB->TotalDataCount = 0;
3448 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003449 /* BB find exact max SMB PDU from sess structure BB */
3450 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003451 pSMB->MaxSetupCount = 0;
3452 pSMB->Reserved = 0;
3453 pSMB->Flags = 0;
3454 pSMB->Timeout = 0;
3455 pSMB->Reserved2 = 0;
3456 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003457 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003458 pSMB->DataCount = 0;
3459 pSMB->DataOffset = 0;
3460 pSMB->SetupCount = 1;
3461 pSMB->Reserved3 = 0;
3462 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3463 byte_count = params + 1 /* pad */ ;
3464 pSMB->TotalParameterCount = cpu_to_le16(params);
3465 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00003466 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003467 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3468 else
3469 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003470 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003471 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003472 pSMB->ByteCount = cpu_to_le16(byte_count);
3473
3474 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3475 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3476 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003477 cFYI(1, "Send error in QPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003478 } else { /* decode response */
3479 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3480
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003481 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3482 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04003483 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003484 rc = -EIO; /* bad smb */
Jeff Layton820a8032011-05-04 08:05:26 -04003485 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
Steve French50c2f752007-07-13 00:33:32 +00003486 rc = -EIO; /* 24 or 26 expected but we do not read
3487 last field */
3488 else if (pFindData) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003489 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003490 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00003491
3492 /* On legacy responses we do not read the last field,
3493 EAsize, fortunately since it varies by subdialect and
3494 also note it differs on Set vs. Get, ie two bytes or 4
3495 bytes depending but we don't care here */
3496 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003497 size = sizeof(FILE_INFO_STANDARD);
3498 else
3499 size = sizeof(FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003500 memcpy((char *) pFindData,
3501 (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003502 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003503 } else
3504 rc = -ENOMEM;
3505 }
3506 cifs_buf_release(pSMB);
3507 if (rc == -EAGAIN)
3508 goto QPathInfoRetry;
3509
3510 return rc;
3511}
3512
3513int
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003514CIFSSMBUnixQFileInfo(const int xid, struct cifsTconInfo *tcon,
3515 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
3516{
3517 struct smb_t2_qfi_req *pSMB = NULL;
3518 struct smb_t2_qfi_rsp *pSMBr = NULL;
3519 int rc = 0;
3520 int bytes_returned;
3521 __u16 params, byte_count;
3522
3523UnixQFileInfoRetry:
3524 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3525 (void **) &pSMBr);
3526 if (rc)
3527 return rc;
3528
3529 params = 2 /* level */ + 2 /* fid */;
3530 pSMB->t2.TotalDataCount = 0;
3531 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3532 /* BB find exact max data count below from sess structure BB */
3533 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3534 pSMB->t2.MaxSetupCount = 0;
3535 pSMB->t2.Reserved = 0;
3536 pSMB->t2.Flags = 0;
3537 pSMB->t2.Timeout = 0;
3538 pSMB->t2.Reserved2 = 0;
3539 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3540 Fid) - 4);
3541 pSMB->t2.DataCount = 0;
3542 pSMB->t2.DataOffset = 0;
3543 pSMB->t2.SetupCount = 1;
3544 pSMB->t2.Reserved3 = 0;
3545 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3546 byte_count = params + 1 /* pad */ ;
3547 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3548 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3549 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3550 pSMB->Pad = 0;
3551 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003552 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003553
3554 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3555 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3556 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00003557 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003558 } else { /* decode response */
3559 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3560
Jeff Layton820a8032011-05-04 08:05:26 -04003561 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Steve Frenchf19159d2010-04-21 04:12:10 +00003562 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response.\n"
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003563 "Unix Extensions can be disabled on mount "
Steve Frenchf19159d2010-04-21 04:12:10 +00003564 "by specifying the nosfu mount option.");
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003565 rc = -EIO; /* bad smb */
3566 } else {
3567 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3568 memcpy((char *) pFindData,
3569 (char *) &pSMBr->hdr.Protocol +
3570 data_offset,
3571 sizeof(FILE_UNIX_BASIC_INFO));
3572 }
3573 }
3574
3575 cifs_buf_release(pSMB);
3576 if (rc == -EAGAIN)
3577 goto UnixQFileInfoRetry;
3578
3579 return rc;
3580}
3581
3582int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003583CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3584 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00003585 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07003586 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003587{
3588/* SMB_QUERY_FILE_UNIX_BASIC */
3589 TRANSACTION2_QPI_REQ *pSMB = NULL;
3590 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3591 int rc = 0;
3592 int bytes_returned = 0;
3593 int name_len;
3594 __u16 params, byte_count;
3595
Joe Perchesb6b38f72010-04-21 03:50:45 +00003596 cFYI(1, "In QPathInfo (Unix) the path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003597UnixQPathInfoRetry:
3598 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3599 (void **) &pSMBr);
3600 if (rc)
3601 return rc;
3602
3603 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3604 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003605 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003606 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003607 name_len++; /* trailing null */
3608 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003609 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003610 name_len = strnlen(searchName, PATH_MAX);
3611 name_len++; /* trailing null */
3612 strncpy(pSMB->FileName, searchName, name_len);
3613 }
3614
Steve French50c2f752007-07-13 00:33:32 +00003615 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003616 pSMB->TotalDataCount = 0;
3617 pSMB->MaxParameterCount = cpu_to_le16(2);
3618 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00003619 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003620 pSMB->MaxSetupCount = 0;
3621 pSMB->Reserved = 0;
3622 pSMB->Flags = 0;
3623 pSMB->Timeout = 0;
3624 pSMB->Reserved2 = 0;
3625 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003626 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003627 pSMB->DataCount = 0;
3628 pSMB->DataOffset = 0;
3629 pSMB->SetupCount = 1;
3630 pSMB->Reserved3 = 0;
3631 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3632 byte_count = params + 1 /* pad */ ;
3633 pSMB->TotalParameterCount = cpu_to_le16(params);
3634 pSMB->ParameterCount = pSMB->TotalParameterCount;
3635 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3636 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003637 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003638 pSMB->ByteCount = cpu_to_le16(byte_count);
3639
3640 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3641 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3642 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003643 cFYI(1, "Send error in QPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003644 } else { /* decode response */
3645 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3646
Jeff Layton820a8032011-05-04 08:05:26 -04003647 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003648 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response.\n"
Steve French1e71f252007-09-20 15:30:07 +00003649 "Unix Extensions can be disabled on mount "
Joe Perchesb6b38f72010-04-21 03:50:45 +00003650 "by specifying the nosfu mount option.");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003651 rc = -EIO; /* bad smb */
3652 } else {
3653 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3654 memcpy((char *) pFindData,
3655 (char *) &pSMBr->hdr.Protocol +
3656 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00003657 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003658 }
3659 }
3660 cifs_buf_release(pSMB);
3661 if (rc == -EAGAIN)
3662 goto UnixQPathInfoRetry;
3663
3664 return rc;
3665}
3666
Linus Torvalds1da177e2005-04-16 15:20:36 -07003667/* xid, tcon, searchName and codepage are input parms, rest are returned */
3668int
3669CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003670 const char *searchName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003671 const struct nls_table *nls_codepage,
Steve French50c2f752007-07-13 00:33:32 +00003672 __u16 *pnetfid,
3673 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003674{
3675/* level 257 SMB_ */
3676 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3677 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00003678 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003679 int rc = 0;
3680 int bytes_returned = 0;
3681 int name_len;
3682 __u16 params, byte_count;
3683
Joe Perchesb6b38f72010-04-21 03:50:45 +00003684 cFYI(1, "In FindFirst for %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003685
3686findFirstRetry:
3687 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3688 (void **) &pSMBr);
3689 if (rc)
3690 return rc;
3691
3692 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3693 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003694 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003695 PATH_MAX, nls_codepage, remap);
3696 /* We can not add the asterik earlier in case
3697 it got remapped to 0xF03A as if it were part of the
3698 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003699 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07003700 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07003701 pSMB->FileName[name_len+1] = 0;
3702 pSMB->FileName[name_len+2] = '*';
3703 pSMB->FileName[name_len+3] = 0;
3704 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003705 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3706 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07003707 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003708 } else { /* BB add check for overrun of SMB buf BB */
3709 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003710/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00003711 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003712 free buffer exit; BB */
3713 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07003714 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07003715 pSMB->FileName[name_len+1] = '*';
3716 pSMB->FileName[name_len+2] = 0;
3717 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003718 }
3719
3720 params = 12 + name_len /* includes null */ ;
3721 pSMB->TotalDataCount = 0; /* no EAs */
3722 pSMB->MaxParameterCount = cpu_to_le16(10);
3723 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3724 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3725 pSMB->MaxSetupCount = 0;
3726 pSMB->Reserved = 0;
3727 pSMB->Flags = 0;
3728 pSMB->Timeout = 0;
3729 pSMB->Reserved2 = 0;
3730 byte_count = params + 1 /* pad */ ;
3731 pSMB->TotalParameterCount = cpu_to_le16(params);
3732 pSMB->ParameterCount = pSMB->TotalParameterCount;
3733 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00003734 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3735 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003736 pSMB->DataCount = 0;
3737 pSMB->DataOffset = 0;
3738 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3739 pSMB->Reserved3 = 0;
3740 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3741 pSMB->SearchAttributes =
3742 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3743 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00003744 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3745 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
Linus Torvalds1da177e2005-04-16 15:20:36 -07003746 CIFS_SEARCH_RETURN_RESUME);
3747 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3748
3749 /* BB what should we set StorageType to? Does it matter? BB */
3750 pSMB->SearchStorageType = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003751 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003752 pSMB->ByteCount = cpu_to_le16(byte_count);
3753
3754 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3755 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003756 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003757
Steve French88274812006-03-09 22:21:45 +00003758 if (rc) {/* BB add logic to retry regular search if Unix search
3759 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003760 /* BB Add code to handle unsupported level rc */
Joe Perchesb6b38f72010-04-21 03:50:45 +00003761 cFYI(1, "Error in FindFirst = %d", rc);
Steve French1982c342005-08-17 12:38:22 -07003762
Steve French88274812006-03-09 22:21:45 +00003763 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003764
3765 /* BB eventually could optimize out free and realloc of buf */
3766 /* for this case */
3767 if (rc == -EAGAIN)
3768 goto findFirstRetry;
3769 } else { /* decode response */
3770 /* BB remember to free buffer if error BB */
3771 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003772 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00003773 unsigned int lnoff;
3774
Linus Torvalds1da177e2005-04-16 15:20:36 -07003775 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00003776 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003777 else
Steve French4b18f2a2008-04-29 00:06:05 +00003778 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003779
3780 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003781 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00003782 psrch_inf->srch_entries_start =
3783 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003784 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003785 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3786 le16_to_cpu(pSMBr->t2.ParameterOffset));
3787
Steve French790fe572007-07-07 19:25:05 +00003788 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00003789 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003790 else
Steve French4b18f2a2008-04-29 00:06:05 +00003791 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003792
Steve French50c2f752007-07-13 00:33:32 +00003793 psrch_inf->entries_in_buffer =
3794 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00003795 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003796 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00003797 lnoff = le16_to_cpu(parms->LastNameOffset);
3798 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3799 lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003800 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00003801 psrch_inf->last_entry = NULL;
3802 return rc;
3803 }
3804
Steve French0752f152008-10-07 20:03:33 +00003805 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00003806 lnoff;
3807
Linus Torvalds1da177e2005-04-16 15:20:36 -07003808 *pnetfid = parms->SearchHandle;
3809 } else {
3810 cifs_buf_release(pSMB);
3811 }
3812 }
3813
3814 return rc;
3815}
3816
3817int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003818 __u16 searchHandle, struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003819{
3820 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3821 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00003822 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003823 char *response_data;
3824 int rc = 0;
3825 int bytes_returned, name_len;
3826 __u16 params, byte_count;
3827
Joe Perchesb6b38f72010-04-21 03:50:45 +00003828 cFYI(1, "In FindNext");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003829
Steve French4b18f2a2008-04-29 00:06:05 +00003830 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003831 return -ENOENT;
3832
3833 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3834 (void **) &pSMBr);
3835 if (rc)
3836 return rc;
3837
Steve French50c2f752007-07-13 00:33:32 +00003838 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003839 byte_count = 0;
3840 pSMB->TotalDataCount = 0; /* no EAs */
3841 pSMB->MaxParameterCount = cpu_to_le16(8);
3842 pSMB->MaxDataCount =
Steve French50c2f752007-07-13 00:33:32 +00003843 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
3844 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003845 pSMB->MaxSetupCount = 0;
3846 pSMB->Reserved = 0;
3847 pSMB->Flags = 0;
3848 pSMB->Timeout = 0;
3849 pSMB->Reserved2 = 0;
3850 pSMB->ParameterOffset = cpu_to_le16(
3851 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3852 pSMB->DataCount = 0;
3853 pSMB->DataOffset = 0;
3854 pSMB->SetupCount = 1;
3855 pSMB->Reserved3 = 0;
3856 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3857 pSMB->SearchHandle = searchHandle; /* always kept as le */
3858 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00003859 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003860 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3861 pSMB->ResumeKey = psrch_inf->resume_key;
3862 pSMB->SearchFlags =
3863 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3864
3865 name_len = psrch_inf->resume_name_len;
3866 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00003867 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003868 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3869 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07003870 /* 14 byte parm len above enough for 2 byte null terminator */
3871 pSMB->ResumeFileName[name_len] = 0;
3872 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003873 } else {
3874 rc = -EINVAL;
3875 goto FNext2_err_exit;
3876 }
3877 byte_count = params + 1 /* pad */ ;
3878 pSMB->TotalParameterCount = cpu_to_le16(params);
3879 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003880 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003881 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00003882
Linus Torvalds1da177e2005-04-16 15:20:36 -07003883 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3884 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003885 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003886 if (rc) {
3887 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00003888 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07003889 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00003890 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003891 } else
Joe Perchesb6b38f72010-04-21 03:50:45 +00003892 cFYI(1, "FindNext returned = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003893 } else { /* decode response */
3894 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00003895
Steve French790fe572007-07-07 19:25:05 +00003896 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00003897 unsigned int lnoff;
3898
Linus Torvalds1da177e2005-04-16 15:20:36 -07003899 /* BB fixme add lock for file (srch_info) struct here */
3900 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00003901 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003902 else
Steve French4b18f2a2008-04-29 00:06:05 +00003903 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003904 response_data = (char *) &pSMBr->hdr.Protocol +
3905 le16_to_cpu(pSMBr->t2.ParameterOffset);
3906 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3907 response_data = (char *)&pSMBr->hdr.Protocol +
3908 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00003909 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00003910 cifs_small_buf_release(
3911 psrch_inf->ntwrk_buf_start);
3912 else
3913 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003914 psrch_inf->srch_entries_start = response_data;
3915 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003916 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00003917 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00003918 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003919 else
Steve French4b18f2a2008-04-29 00:06:05 +00003920 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00003921 psrch_inf->entries_in_buffer =
3922 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003923 psrch_inf->index_of_last_entry +=
3924 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00003925 lnoff = le16_to_cpu(parms->LastNameOffset);
3926 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3927 lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003928 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00003929 psrch_inf->last_entry = NULL;
3930 return rc;
3931 } else
3932 psrch_inf->last_entry =
3933 psrch_inf->srch_entries_start + lnoff;
3934
Joe Perchesb6b38f72010-04-21 03:50:45 +00003935/* cFYI(1, "fnxt2 entries in buf %d index_of_last %d",
3936 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003937
3938 /* BB fixme add unlock here */
3939 }
3940
3941 }
3942
3943 /* BB On error, should we leave previous search buf (and count and
3944 last entry fields) intact or free the previous one? */
3945
3946 /* Note: On -EAGAIN error only caller can retry on handle based calls
3947 since file handle passed in no longer valid */
3948FNext2_err_exit:
3949 if (rc != 0)
3950 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003951 return rc;
3952}
3953
3954int
Steve French50c2f752007-07-13 00:33:32 +00003955CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
3956 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003957{
3958 int rc = 0;
3959 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003960
Joe Perchesb6b38f72010-04-21 03:50:45 +00003961 cFYI(1, "In CIFSSMBFindClose");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003962 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3963
3964 /* no sense returning error if session restarted
3965 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00003966 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003967 return 0;
3968 if (rc)
3969 return rc;
3970
Linus Torvalds1da177e2005-04-16 15:20:36 -07003971 pSMB->FileID = searchHandle;
3972 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00003973 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003974 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003975 cERROR(1, "Send error in FindClose = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00003976
Steve Frencha4544342005-08-24 13:59:35 -07003977 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003978
3979 /* Since session is dead, search handle closed on server already */
3980 if (rc == -EAGAIN)
3981 rc = 0;
3982
3983 return rc;
3984}
3985
Linus Torvalds1da177e2005-04-16 15:20:36 -07003986int
3987CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003988 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003989 __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00003990 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003991{
3992 int rc = 0;
3993 TRANSACTION2_QPI_REQ *pSMB = NULL;
3994 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3995 int name_len, bytes_returned;
3996 __u16 params, byte_count;
3997
Joe Perchesb6b38f72010-04-21 03:50:45 +00003998 cFYI(1, "In GetSrvInodeNum for %s", searchName);
Steve French790fe572007-07-07 19:25:05 +00003999 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00004000 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004001
4002GetInodeNumberRetry:
4003 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004004 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004005 if (rc)
4006 return rc;
4007
Linus Torvalds1da177e2005-04-16 15:20:36 -07004008 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4009 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004010 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French50c2f752007-07-13 00:33:32 +00004011 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004012 name_len++; /* trailing null */
4013 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004014 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004015 name_len = strnlen(searchName, PATH_MAX);
4016 name_len++; /* trailing null */
4017 strncpy(pSMB->FileName, searchName, name_len);
4018 }
4019
4020 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4021 pSMB->TotalDataCount = 0;
4022 pSMB->MaxParameterCount = cpu_to_le16(2);
4023 /* BB find exact max data count below from sess structure BB */
4024 pSMB->MaxDataCount = cpu_to_le16(4000);
4025 pSMB->MaxSetupCount = 0;
4026 pSMB->Reserved = 0;
4027 pSMB->Flags = 0;
4028 pSMB->Timeout = 0;
4029 pSMB->Reserved2 = 0;
4030 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004031 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004032 pSMB->DataCount = 0;
4033 pSMB->DataOffset = 0;
4034 pSMB->SetupCount = 1;
4035 pSMB->Reserved3 = 0;
4036 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4037 byte_count = params + 1 /* pad */ ;
4038 pSMB->TotalParameterCount = cpu_to_le16(params);
4039 pSMB->ParameterCount = pSMB->TotalParameterCount;
4040 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4041 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004042 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004043 pSMB->ByteCount = cpu_to_le16(byte_count);
4044
4045 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4046 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4047 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004048 cFYI(1, "error %d in QueryInternalInfo", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004049 } else {
4050 /* decode response */
4051 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004052 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04004053 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004054 /* If rc should we check for EOPNOSUPP and
4055 disable the srvino flag? or in caller? */
4056 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00004057 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004058 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4059 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00004060 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004061 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00004062 if (count < 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004063 cFYI(1, "Illegal size ret in QryIntrnlInf");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004064 rc = -EIO;
4065 goto GetInodeNumOut;
4066 }
4067 pfinfo = (struct file_internal_info *)
4068 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00004069 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004070 }
4071 }
4072GetInodeNumOut:
4073 cifs_buf_release(pSMB);
4074 if (rc == -EAGAIN)
4075 goto GetInodeNumberRetry;
4076 return rc;
4077}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004078
Igor Mammedovfec45852008-05-16 13:06:30 +04004079/* parses DFS refferal V3 structure
4080 * caller is responsible for freeing target_nodes
4081 * returns:
4082 * on success - 0
4083 * on failure - errno
4084 */
4085static int
Steve Frencha1fe78f2008-05-16 18:48:38 +00004086parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
Igor Mammedovfec45852008-05-16 13:06:30 +04004087 unsigned int *num_of_nodes,
4088 struct dfs_info3_param **target_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004089 const struct nls_table *nls_codepage, int remap,
4090 const char *searchName)
Igor Mammedovfec45852008-05-16 13:06:30 +04004091{
4092 int i, rc = 0;
4093 char *data_end;
4094 bool is_unicode;
4095 struct dfs_referral_level_3 *ref;
4096
Harvey Harrison5ca33c62008-07-23 17:45:58 -07004097 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4098 is_unicode = true;
4099 else
4100 is_unicode = false;
Igor Mammedovfec45852008-05-16 13:06:30 +04004101 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
4102
4103 if (*num_of_nodes < 1) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004104 cERROR(1, "num_referrals: must be at least > 0,"
4105 "but we get num_referrals = %d\n", *num_of_nodes);
Igor Mammedovfec45852008-05-16 13:06:30 +04004106 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004107 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004108 }
4109
4110 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
Al Viro1d92cfd2008-06-02 10:59:02 +01004111 if (ref->VersionNumber != cpu_to_le16(3)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004112 cERROR(1, "Referrals of V%d version are not supported,"
4113 "should be V3", le16_to_cpu(ref->VersionNumber));
Igor Mammedovfec45852008-05-16 13:06:30 +04004114 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004115 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004116 }
4117
4118 /* get the upper boundary of the resp buffer */
4119 data_end = (char *)(&(pSMBr->PathConsumed)) +
4120 le16_to_cpu(pSMBr->t2.DataCount);
4121
Steve Frenchf19159d2010-04-21 04:12:10 +00004122 cFYI(1, "num_referrals: %d dfs flags: 0x%x ...\n",
Igor Mammedovfec45852008-05-16 13:06:30 +04004123 *num_of_nodes,
Joe Perchesb6b38f72010-04-21 03:50:45 +00004124 le32_to_cpu(pSMBr->DFSFlags));
Igor Mammedovfec45852008-05-16 13:06:30 +04004125
4126 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
4127 *num_of_nodes, GFP_KERNEL);
4128 if (*target_nodes == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004129 cERROR(1, "Failed to allocate buffer for target_nodes\n");
Igor Mammedovfec45852008-05-16 13:06:30 +04004130 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004131 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004132 }
4133
Daniel Mack3ad2f3f2010-02-03 08:01:28 +08004134 /* collect necessary data from referrals */
Igor Mammedovfec45852008-05-16 13:06:30 +04004135 for (i = 0; i < *num_of_nodes; i++) {
4136 char *temp;
4137 int max_len;
4138 struct dfs_info3_param *node = (*target_nodes)+i;
4139
Steve French0e0d2cf2009-05-01 05:27:32 +00004140 node->flags = le32_to_cpu(pSMBr->DFSFlags);
Igor Mammedov2c556082008-10-23 13:58:42 +04004141 if (is_unicode) {
Jeff Layton331c3132008-12-17 06:31:53 -05004142 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4143 GFP_KERNEL);
Steve French2920ee22009-08-31 15:27:26 +00004144 if (tmp == NULL) {
4145 rc = -ENOMEM;
4146 goto parse_DFS_referrals_exit;
4147 }
Igor Mammedov2c556082008-10-23 13:58:42 +04004148 cifsConvertToUCS((__le16 *) tmp, searchName,
4149 PATH_MAX, nls_codepage, remap);
Jeff Layton69f801f2009-04-30 06:46:32 -04004150 node->path_consumed = cifs_ucs2_bytes(tmp,
4151 le16_to_cpu(pSMBr->PathConsumed),
Igor Mammedov2c556082008-10-23 13:58:42 +04004152 nls_codepage);
4153 kfree(tmp);
4154 } else
4155 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4156
Igor Mammedovfec45852008-05-16 13:06:30 +04004157 node->server_type = le16_to_cpu(ref->ServerType);
4158 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4159
4160 /* copy DfsPath */
4161 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4162 max_len = data_end - temp;
Steve Frenchd185cda2009-04-30 17:45:10 +00004163 node->path_name = cifs_strndup_from_ucs(temp, max_len,
4164 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004165 if (!node->path_name) {
4166 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004167 goto parse_DFS_referrals_exit;
Jeff Layton066ce682009-04-30 07:16:14 -04004168 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004169
4170 /* copy link target UNC */
4171 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4172 max_len = data_end - temp;
Steve Frenchd185cda2009-04-30 17:45:10 +00004173 node->node_name = cifs_strndup_from_ucs(temp, max_len,
4174 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004175 if (!node->node_name)
4176 rc = -ENOMEM;
Igor Mammedovfec45852008-05-16 13:06:30 +04004177 }
4178
Steve Frencha1fe78f2008-05-16 18:48:38 +00004179parse_DFS_referrals_exit:
Igor Mammedovfec45852008-05-16 13:06:30 +04004180 if (rc) {
4181 free_dfs_info_array(*target_nodes, *num_of_nodes);
4182 *target_nodes = NULL;
4183 *num_of_nodes = 0;
4184 }
4185 return rc;
4186}
4187
Linus Torvalds1da177e2005-04-16 15:20:36 -07004188int
4189CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
4190 const unsigned char *searchName,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004191 struct dfs_info3_param **target_nodes,
4192 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004193 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004194{
4195/* TRANS2_GET_DFS_REFERRAL */
4196 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4197 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004198 int rc = 0;
4199 int bytes_returned;
4200 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004201 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004202 *num_of_nodes = 0;
4203 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004204
Joe Perchesb6b38f72010-04-21 03:50:45 +00004205 cFYI(1, "In GetDFSRefer the path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004206 if (ses == NULL)
4207 return -ENODEV;
4208getDFSRetry:
4209 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4210 (void **) &pSMBr);
4211 if (rc)
4212 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004213
4214 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004215 but should never be null here anyway */
4216 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004217 pSMB->hdr.Tid = ses->ipc_tid;
4218 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004219 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004220 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004221 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004222 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004223
4224 if (ses->capabilities & CAP_UNICODE) {
4225 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4226 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004227 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07004228 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004229 name_len++; /* trailing null */
4230 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004231 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004232 name_len = strnlen(searchName, PATH_MAX);
4233 name_len++; /* trailing null */
4234 strncpy(pSMB->RequestFileName, searchName, name_len);
4235 }
4236
Steve French790fe572007-07-07 19:25:05 +00004237 if (ses->server) {
4238 if (ses->server->secMode &
Steve French1a4e15a2006-10-12 21:33:51 +00004239 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4240 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4241 }
4242
Steve French50c2f752007-07-13 00:33:32 +00004243 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004244
Linus Torvalds1da177e2005-04-16 15:20:36 -07004245 params = 2 /* level */ + name_len /*includes null */ ;
4246 pSMB->TotalDataCount = 0;
4247 pSMB->DataCount = 0;
4248 pSMB->DataOffset = 0;
4249 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004250 /* BB find exact max SMB PDU from sess structure BB */
4251 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004252 pSMB->MaxSetupCount = 0;
4253 pSMB->Reserved = 0;
4254 pSMB->Flags = 0;
4255 pSMB->Timeout = 0;
4256 pSMB->Reserved2 = 0;
4257 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004258 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004259 pSMB->SetupCount = 1;
4260 pSMB->Reserved3 = 0;
4261 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4262 byte_count = params + 3 /* pad */ ;
4263 pSMB->ParameterCount = cpu_to_le16(params);
4264 pSMB->TotalParameterCount = pSMB->ParameterCount;
4265 pSMB->MaxReferralLevel = cpu_to_le16(3);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004266 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004267 pSMB->ByteCount = cpu_to_le16(byte_count);
4268
4269 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4270 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4271 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004272 cFYI(1, "Send error in GetDFSRefer = %d", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004273 goto GetDFSRefExit;
4274 }
4275 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004276
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004277 /* BB Also check if enough total bytes returned? */
Jeff Layton820a8032011-05-04 08:05:26 -04004278 if (rc || get_bcc(&pSMBr->hdr) < 17) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004279 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004280 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004281 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004282
Joe Perchesb6b38f72010-04-21 03:50:45 +00004283 cFYI(1, "Decoding GetDFSRefer response BCC: %d Offset %d",
Jeff Layton820a8032011-05-04 08:05:26 -04004284 get_bcc(&pSMBr->hdr),
Joe Perchesb6b38f72010-04-21 03:50:45 +00004285 le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04004286
4287 /* parse returned result into more usable form */
Steve Frencha1fe78f2008-05-16 18:48:38 +00004288 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004289 target_nodes, nls_codepage, remap,
4290 searchName);
Igor Mammedovfec45852008-05-16 13:06:30 +04004291
Linus Torvalds1da177e2005-04-16 15:20:36 -07004292GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004293 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004294
4295 if (rc == -EAGAIN)
4296 goto getDFSRetry;
4297
4298 return rc;
4299}
4300
Steve French20962432005-09-21 22:05:57 -07004301/* Query File System Info such as free space to old servers such as Win 9x */
4302int
4303SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4304{
4305/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4306 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4307 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4308 FILE_SYSTEM_ALLOC_INFO *response_data;
4309 int rc = 0;
4310 int bytes_returned = 0;
4311 __u16 params, byte_count;
4312
Joe Perchesb6b38f72010-04-21 03:50:45 +00004313 cFYI(1, "OldQFSInfo");
Steve French20962432005-09-21 22:05:57 -07004314oldQFSInfoRetry:
4315 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4316 (void **) &pSMBr);
4317 if (rc)
4318 return rc;
Steve French20962432005-09-21 22:05:57 -07004319
4320 params = 2; /* level */
4321 pSMB->TotalDataCount = 0;
4322 pSMB->MaxParameterCount = cpu_to_le16(2);
4323 pSMB->MaxDataCount = cpu_to_le16(1000);
4324 pSMB->MaxSetupCount = 0;
4325 pSMB->Reserved = 0;
4326 pSMB->Flags = 0;
4327 pSMB->Timeout = 0;
4328 pSMB->Reserved2 = 0;
4329 byte_count = params + 1 /* pad */ ;
4330 pSMB->TotalParameterCount = cpu_to_le16(params);
4331 pSMB->ParameterCount = pSMB->TotalParameterCount;
4332 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4333 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4334 pSMB->DataCount = 0;
4335 pSMB->DataOffset = 0;
4336 pSMB->SetupCount = 1;
4337 pSMB->Reserved3 = 0;
4338 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4339 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004340 inc_rfc1001_len(pSMB, byte_count);
Steve French20962432005-09-21 22:05:57 -07004341 pSMB->ByteCount = cpu_to_le16(byte_count);
4342
4343 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4344 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4345 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004346 cFYI(1, "Send error in QFSInfo = %d", rc);
Steve French20962432005-09-21 22:05:57 -07004347 } else { /* decode response */
4348 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4349
Jeff Layton820a8032011-05-04 08:05:26 -04004350 if (rc || get_bcc(&pSMBr->hdr) < 18)
Steve French20962432005-09-21 22:05:57 -07004351 rc = -EIO; /* bad smb */
4352 else {
4353 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004354 cFYI(1, "qfsinf resp BCC: %d Offset %d",
Jeff Layton820a8032011-05-04 08:05:26 -04004355 get_bcc(&pSMBr->hdr), data_offset);
Steve French20962432005-09-21 22:05:57 -07004356
Steve French50c2f752007-07-13 00:33:32 +00004357 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004358 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4359 FSData->f_bsize =
4360 le16_to_cpu(response_data->BytesPerSector) *
4361 le32_to_cpu(response_data->
4362 SectorsPerAllocationUnit);
4363 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004364 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004365 FSData->f_bfree = FSData->f_bavail =
4366 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004367 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
4368 (unsigned long long)FSData->f_blocks,
4369 (unsigned long long)FSData->f_bfree,
4370 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07004371 }
4372 }
4373 cifs_buf_release(pSMB);
4374
4375 if (rc == -EAGAIN)
4376 goto oldQFSInfoRetry;
4377
4378 return rc;
4379}
4380
Linus Torvalds1da177e2005-04-16 15:20:36 -07004381int
Steve French737b7582005-04-28 22:41:06 -07004382CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004383{
4384/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4385 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4386 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4387 FILE_SYSTEM_INFO *response_data;
4388 int rc = 0;
4389 int bytes_returned = 0;
4390 __u16 params, byte_count;
4391
Joe Perchesb6b38f72010-04-21 03:50:45 +00004392 cFYI(1, "In QFSInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004393QFSInfoRetry:
4394 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4395 (void **) &pSMBr);
4396 if (rc)
4397 return rc;
4398
4399 params = 2; /* level */
4400 pSMB->TotalDataCount = 0;
4401 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004402 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004403 pSMB->MaxSetupCount = 0;
4404 pSMB->Reserved = 0;
4405 pSMB->Flags = 0;
4406 pSMB->Timeout = 0;
4407 pSMB->Reserved2 = 0;
4408 byte_count = params + 1 /* pad */ ;
4409 pSMB->TotalParameterCount = cpu_to_le16(params);
4410 pSMB->ParameterCount = pSMB->TotalParameterCount;
4411 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004412 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004413 pSMB->DataCount = 0;
4414 pSMB->DataOffset = 0;
4415 pSMB->SetupCount = 1;
4416 pSMB->Reserved3 = 0;
4417 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4418 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004419 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004420 pSMB->ByteCount = cpu_to_le16(byte_count);
4421
4422 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4423 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4424 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004425 cFYI(1, "Send error in QFSInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004426 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00004427 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004428
Jeff Layton820a8032011-05-04 08:05:26 -04004429 if (rc || get_bcc(&pSMBr->hdr) < 24)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004430 rc = -EIO; /* bad smb */
4431 else {
4432 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004433
4434 response_data =
4435 (FILE_SYSTEM_INFO
4436 *) (((char *) &pSMBr->hdr.Protocol) +
4437 data_offset);
4438 FSData->f_bsize =
4439 le32_to_cpu(response_data->BytesPerSector) *
4440 le32_to_cpu(response_data->
4441 SectorsPerAllocationUnit);
4442 FSData->f_blocks =
4443 le64_to_cpu(response_data->TotalAllocationUnits);
4444 FSData->f_bfree = FSData->f_bavail =
4445 le64_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004446 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
4447 (unsigned long long)FSData->f_blocks,
4448 (unsigned long long)FSData->f_bfree,
4449 FSData->f_bsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004450 }
4451 }
4452 cifs_buf_release(pSMB);
4453
4454 if (rc == -EAGAIN)
4455 goto QFSInfoRetry;
4456
4457 return rc;
4458}
4459
4460int
Steve French737b7582005-04-28 22:41:06 -07004461CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004462{
4463/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4464 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4465 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4466 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4467 int rc = 0;
4468 int bytes_returned = 0;
4469 __u16 params, byte_count;
4470
Joe Perchesb6b38f72010-04-21 03:50:45 +00004471 cFYI(1, "In QFSAttributeInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004472QFSAttributeRetry:
4473 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4474 (void **) &pSMBr);
4475 if (rc)
4476 return rc;
4477
4478 params = 2; /* level */
4479 pSMB->TotalDataCount = 0;
4480 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004481 /* BB find exact max SMB PDU from sess structure BB */
4482 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004483 pSMB->MaxSetupCount = 0;
4484 pSMB->Reserved = 0;
4485 pSMB->Flags = 0;
4486 pSMB->Timeout = 0;
4487 pSMB->Reserved2 = 0;
4488 byte_count = params + 1 /* pad */ ;
4489 pSMB->TotalParameterCount = cpu_to_le16(params);
4490 pSMB->ParameterCount = pSMB->TotalParameterCount;
4491 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004492 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004493 pSMB->DataCount = 0;
4494 pSMB->DataOffset = 0;
4495 pSMB->SetupCount = 1;
4496 pSMB->Reserved3 = 0;
4497 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4498 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004499 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004500 pSMB->ByteCount = cpu_to_le16(byte_count);
4501
4502 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4503 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4504 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004505 cERROR(1, "Send error in QFSAttributeInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004506 } else { /* decode response */
4507 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4508
Jeff Layton820a8032011-05-04 08:05:26 -04004509 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Steve French50c2f752007-07-13 00:33:32 +00004510 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004511 rc = -EIO; /* bad smb */
4512 } else {
4513 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4514 response_data =
4515 (FILE_SYSTEM_ATTRIBUTE_INFO
4516 *) (((char *) &pSMBr->hdr.Protocol) +
4517 data_offset);
4518 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004519 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004520 }
4521 }
4522 cifs_buf_release(pSMB);
4523
4524 if (rc == -EAGAIN)
4525 goto QFSAttributeRetry;
4526
4527 return rc;
4528}
4529
4530int
Steve French737b7582005-04-28 22:41:06 -07004531CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004532{
4533/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4534 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4535 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4536 FILE_SYSTEM_DEVICE_INFO *response_data;
4537 int rc = 0;
4538 int bytes_returned = 0;
4539 __u16 params, byte_count;
4540
Joe Perchesb6b38f72010-04-21 03:50:45 +00004541 cFYI(1, "In QFSDeviceInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004542QFSDeviceRetry:
4543 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4544 (void **) &pSMBr);
4545 if (rc)
4546 return rc;
4547
4548 params = 2; /* level */
4549 pSMB->TotalDataCount = 0;
4550 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004551 /* BB find exact max SMB PDU from sess structure BB */
4552 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004553 pSMB->MaxSetupCount = 0;
4554 pSMB->Reserved = 0;
4555 pSMB->Flags = 0;
4556 pSMB->Timeout = 0;
4557 pSMB->Reserved2 = 0;
4558 byte_count = params + 1 /* pad */ ;
4559 pSMB->TotalParameterCount = cpu_to_le16(params);
4560 pSMB->ParameterCount = pSMB->TotalParameterCount;
4561 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004562 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004563
4564 pSMB->DataCount = 0;
4565 pSMB->DataOffset = 0;
4566 pSMB->SetupCount = 1;
4567 pSMB->Reserved3 = 0;
4568 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4569 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004570 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004571 pSMB->ByteCount = cpu_to_le16(byte_count);
4572
4573 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4574 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4575 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004576 cFYI(1, "Send error in QFSDeviceInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004577 } else { /* decode response */
4578 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4579
Jeff Layton820a8032011-05-04 08:05:26 -04004580 if (rc || get_bcc(&pSMBr->hdr) <
4581 sizeof(FILE_SYSTEM_DEVICE_INFO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004582 rc = -EIO; /* bad smb */
4583 else {
4584 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4585 response_data =
Steve French737b7582005-04-28 22:41:06 -07004586 (FILE_SYSTEM_DEVICE_INFO *)
4587 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004588 data_offset);
4589 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004590 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004591 }
4592 }
4593 cifs_buf_release(pSMB);
4594
4595 if (rc == -EAGAIN)
4596 goto QFSDeviceRetry;
4597
4598 return rc;
4599}
4600
4601int
Steve French737b7582005-04-28 22:41:06 -07004602CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004603{
4604/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4605 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4606 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4607 FILE_SYSTEM_UNIX_INFO *response_data;
4608 int rc = 0;
4609 int bytes_returned = 0;
4610 __u16 params, byte_count;
4611
Joe Perchesb6b38f72010-04-21 03:50:45 +00004612 cFYI(1, "In QFSUnixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004613QFSUnixRetry:
Jeff Laytonf5695992010-09-29 15:27:08 -04004614 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
4615 (void **) &pSMB, (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004616 if (rc)
4617 return rc;
4618
4619 params = 2; /* level */
4620 pSMB->TotalDataCount = 0;
4621 pSMB->DataCount = 0;
4622 pSMB->DataOffset = 0;
4623 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004624 /* BB find exact max SMB PDU from sess structure BB */
4625 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004626 pSMB->MaxSetupCount = 0;
4627 pSMB->Reserved = 0;
4628 pSMB->Flags = 0;
4629 pSMB->Timeout = 0;
4630 pSMB->Reserved2 = 0;
4631 byte_count = params + 1 /* pad */ ;
4632 pSMB->ParameterCount = cpu_to_le16(params);
4633 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004634 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4635 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004636 pSMB->SetupCount = 1;
4637 pSMB->Reserved3 = 0;
4638 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4639 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004640 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004641 pSMB->ByteCount = cpu_to_le16(byte_count);
4642
4643 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4644 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4645 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004646 cERROR(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004647 } else { /* decode response */
4648 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4649
Jeff Layton820a8032011-05-04 08:05:26 -04004650 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004651 rc = -EIO; /* bad smb */
4652 } else {
4653 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4654 response_data =
4655 (FILE_SYSTEM_UNIX_INFO
4656 *) (((char *) &pSMBr->hdr.Protocol) +
4657 data_offset);
4658 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004659 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004660 }
4661 }
4662 cifs_buf_release(pSMB);
4663
4664 if (rc == -EAGAIN)
4665 goto QFSUnixRetry;
4666
4667
4668 return rc;
4669}
4670
Jeremy Allisonac670552005-06-22 17:26:35 -07004671int
Steve French45abc6e2005-06-23 13:42:03 -05004672CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07004673{
4674/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4675 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4676 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4677 int rc = 0;
4678 int bytes_returned = 0;
4679 __u16 params, param_offset, offset, byte_count;
4680
Joe Perchesb6b38f72010-04-21 03:50:45 +00004681 cFYI(1, "In SETFSUnixInfo");
Jeremy Allisonac670552005-06-22 17:26:35 -07004682SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00004683 /* BB switch to small buf init to save memory */
Jeff Laytonf5695992010-09-29 15:27:08 -04004684 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
4685 (void **) &pSMB, (void **) &pSMBr);
Jeremy Allisonac670552005-06-22 17:26:35 -07004686 if (rc)
4687 return rc;
4688
4689 params = 4; /* 2 bytes zero followed by info level. */
4690 pSMB->MaxSetupCount = 0;
4691 pSMB->Reserved = 0;
4692 pSMB->Flags = 0;
4693 pSMB->Timeout = 0;
4694 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00004695 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4696 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07004697 offset = param_offset + params;
4698
4699 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00004700 /* BB find exact max SMB PDU from sess structure BB */
4701 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07004702 pSMB->SetupCount = 1;
4703 pSMB->Reserved3 = 0;
4704 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4705 byte_count = 1 /* pad */ + params + 12;
4706
4707 pSMB->DataCount = cpu_to_le16(12);
4708 pSMB->ParameterCount = cpu_to_le16(params);
4709 pSMB->TotalDataCount = pSMB->DataCount;
4710 pSMB->TotalParameterCount = pSMB->ParameterCount;
4711 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4712 pSMB->DataOffset = cpu_to_le16(offset);
4713
4714 /* Params. */
4715 pSMB->FileNum = 0;
4716 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4717
4718 /* Data. */
4719 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4720 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4721 pSMB->ClientUnixCap = cpu_to_le64(cap);
4722
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004723 inc_rfc1001_len(pSMB, byte_count);
Jeremy Allisonac670552005-06-22 17:26:35 -07004724 pSMB->ByteCount = cpu_to_le16(byte_count);
4725
4726 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4727 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4728 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004729 cERROR(1, "Send error in SETFSUnixInfo = %d", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07004730 } else { /* decode response */
4731 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00004732 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07004733 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07004734 }
4735 cifs_buf_release(pSMB);
4736
4737 if (rc == -EAGAIN)
4738 goto SETFSUnixRetry;
4739
4740 return rc;
4741}
4742
4743
Linus Torvalds1da177e2005-04-16 15:20:36 -07004744
4745int
4746CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004747 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004748{
4749/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4750 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4751 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4752 FILE_SYSTEM_POSIX_INFO *response_data;
4753 int rc = 0;
4754 int bytes_returned = 0;
4755 __u16 params, byte_count;
4756
Joe Perchesb6b38f72010-04-21 03:50:45 +00004757 cFYI(1, "In QFSPosixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004758QFSPosixRetry:
4759 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4760 (void **) &pSMBr);
4761 if (rc)
4762 return rc;
4763
4764 params = 2; /* level */
4765 pSMB->TotalDataCount = 0;
4766 pSMB->DataCount = 0;
4767 pSMB->DataOffset = 0;
4768 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004769 /* BB find exact max SMB PDU from sess structure BB */
4770 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004771 pSMB->MaxSetupCount = 0;
4772 pSMB->Reserved = 0;
4773 pSMB->Flags = 0;
4774 pSMB->Timeout = 0;
4775 pSMB->Reserved2 = 0;
4776 byte_count = params + 1 /* pad */ ;
4777 pSMB->ParameterCount = cpu_to_le16(params);
4778 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004779 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4780 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004781 pSMB->SetupCount = 1;
4782 pSMB->Reserved3 = 0;
4783 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4784 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004785 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004786 pSMB->ByteCount = cpu_to_le16(byte_count);
4787
4788 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4789 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4790 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004791 cFYI(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004792 } else { /* decode response */
4793 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4794
Jeff Layton820a8032011-05-04 08:05:26 -04004795 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004796 rc = -EIO; /* bad smb */
4797 } else {
4798 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4799 response_data =
4800 (FILE_SYSTEM_POSIX_INFO
4801 *) (((char *) &pSMBr->hdr.Protocol) +
4802 data_offset);
4803 FSData->f_bsize =
4804 le32_to_cpu(response_data->BlockSize);
4805 FSData->f_blocks =
4806 le64_to_cpu(response_data->TotalBlocks);
4807 FSData->f_bfree =
4808 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00004809 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004810 FSData->f_bavail = FSData->f_bfree;
4811 } else {
4812 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00004813 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004814 }
Steve French790fe572007-07-07 19:25:05 +00004815 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004816 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00004817 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00004818 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004819 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00004820 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004821 }
4822 }
4823 cifs_buf_release(pSMB);
4824
4825 if (rc == -EAGAIN)
4826 goto QFSPosixRetry;
4827
4828 return rc;
4829}
4830
4831
Steve French50c2f752007-07-13 00:33:32 +00004832/* We can not use write of zero bytes trick to
4833 set file size due to need for large file support. Also note that
4834 this SetPathInfo is preferred to SetFileInfo based method in next
Linus Torvalds1da177e2005-04-16 15:20:36 -07004835 routine which is only needed to work around a sharing violation bug
4836 in Samba which this routine can run into */
4837
4838int
4839CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French4b18f2a2008-04-29 00:06:05 +00004840 __u64 size, bool SetAllocation,
Steve French737b7582005-04-28 22:41:06 -07004841 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004842{
4843 struct smb_com_transaction2_spi_req *pSMB = NULL;
4844 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4845 struct file_end_of_file_info *parm_data;
4846 int name_len;
4847 int rc = 0;
4848 int bytes_returned = 0;
4849 __u16 params, byte_count, data_count, param_offset, offset;
4850
Joe Perchesb6b38f72010-04-21 03:50:45 +00004851 cFYI(1, "In SetEOF");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004852SetEOFRetry:
4853 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4854 (void **) &pSMBr);
4855 if (rc)
4856 return rc;
4857
4858 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4859 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004860 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004861 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004862 name_len++; /* trailing null */
4863 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004864 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004865 name_len = strnlen(fileName, PATH_MAX);
4866 name_len++; /* trailing null */
4867 strncpy(pSMB->FileName, fileName, name_len);
4868 }
4869 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00004870 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004871 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07004872 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004873 pSMB->MaxSetupCount = 0;
4874 pSMB->Reserved = 0;
4875 pSMB->Flags = 0;
4876 pSMB->Timeout = 0;
4877 pSMB->Reserved2 = 0;
4878 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00004879 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004880 offset = param_offset + params;
Steve French790fe572007-07-07 19:25:05 +00004881 if (SetAllocation) {
Steve French50c2f752007-07-13 00:33:32 +00004882 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4883 pSMB->InformationLevel =
4884 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4885 else
4886 pSMB->InformationLevel =
4887 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4888 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004889 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4890 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004891 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004892 else
4893 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004894 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004895 }
4896
4897 parm_data =
4898 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4899 offset);
4900 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4901 pSMB->DataOffset = cpu_to_le16(offset);
4902 pSMB->SetupCount = 1;
4903 pSMB->Reserved3 = 0;
4904 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4905 byte_count = 3 /* pad */ + params + data_count;
4906 pSMB->DataCount = cpu_to_le16(data_count);
4907 pSMB->TotalDataCount = pSMB->DataCount;
4908 pSMB->ParameterCount = cpu_to_le16(params);
4909 pSMB->TotalParameterCount = pSMB->ParameterCount;
4910 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004911 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004912 parm_data->FileSize = cpu_to_le64(size);
4913 pSMB->ByteCount = cpu_to_le16(byte_count);
4914 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4915 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004916 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00004917 cFYI(1, "SetPathInfo (file size) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004918
4919 cifs_buf_release(pSMB);
4920
4921 if (rc == -EAGAIN)
4922 goto SetEOFRetry;
4923
4924 return rc;
4925}
4926
4927int
Steve French50c2f752007-07-13 00:33:32 +00004928CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
Steve French4b18f2a2008-04-29 00:06:05 +00004929 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004930{
4931 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004932 struct file_end_of_file_info *parm_data;
4933 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004934 __u16 params, param_offset, offset, byte_count, count;
4935
Joe Perchesb6b38f72010-04-21 03:50:45 +00004936 cFYI(1, "SetFileSize (via SetFileInfo) %lld",
4937 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07004938 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4939
Linus Torvalds1da177e2005-04-16 15:20:36 -07004940 if (rc)
4941 return rc;
4942
4943 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4944 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00004945
Linus Torvalds1da177e2005-04-16 15:20:36 -07004946 params = 6;
4947 pSMB->MaxSetupCount = 0;
4948 pSMB->Reserved = 0;
4949 pSMB->Flags = 0;
4950 pSMB->Timeout = 0;
4951 pSMB->Reserved2 = 0;
4952 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4953 offset = param_offset + params;
4954
Linus Torvalds1da177e2005-04-16 15:20:36 -07004955 count = sizeof(struct file_end_of_file_info);
4956 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004957 /* BB find exact max SMB PDU from sess structure BB */
4958 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004959 pSMB->SetupCount = 1;
4960 pSMB->Reserved3 = 0;
4961 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4962 byte_count = 3 /* pad */ + params + count;
4963 pSMB->DataCount = cpu_to_le16(count);
4964 pSMB->ParameterCount = cpu_to_le16(params);
4965 pSMB->TotalDataCount = pSMB->DataCount;
4966 pSMB->TotalParameterCount = pSMB->ParameterCount;
4967 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4968 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00004969 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
4970 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004971 pSMB->DataOffset = cpu_to_le16(offset);
4972 parm_data->FileSize = cpu_to_le64(size);
4973 pSMB->Fid = fid;
Steve French790fe572007-07-07 19:25:05 +00004974 if (SetAllocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004975 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4976 pSMB->InformationLevel =
4977 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4978 else
4979 pSMB->InformationLevel =
4980 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00004981 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004982 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4983 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004984 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004985 else
4986 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004987 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004988 }
4989 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004990 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004991 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French133672e2007-11-13 22:41:37 +00004992 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004993 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004994 cFYI(1, "Send error in SetFileInfo (SetFileSize) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004995 }
4996
Steve French50c2f752007-07-13 00:33:32 +00004997 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004998 since file handle passed in no longer valid */
4999
5000 return rc;
5001}
5002
Steve French50c2f752007-07-13 00:33:32 +00005003/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07005004 an open handle, rather than by pathname - this is awkward due to
5005 potential access conflicts on the open, but it is unavoidable for these
5006 old servers since the only other choice is to go from 100 nanosecond DCE
5007 time and resort to the original setpathinfo level which takes the ancient
5008 DOS time format with 2 second granularity */
5009int
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005010CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon,
5011 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005012{
5013 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005014 char *data_offset;
5015 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005016 __u16 params, param_offset, offset, byte_count, count;
5017
Joe Perchesb6b38f72010-04-21 03:50:45 +00005018 cFYI(1, "Set Times (via SetFileInfo)");
Steve Frenchcd634992005-04-28 22:41:10 -07005019 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5020
Linus Torvalds1da177e2005-04-16 15:20:36 -07005021 if (rc)
5022 return rc;
5023
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005024 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5025 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005026
Linus Torvalds1da177e2005-04-16 15:20:36 -07005027 params = 6;
5028 pSMB->MaxSetupCount = 0;
5029 pSMB->Reserved = 0;
5030 pSMB->Flags = 0;
5031 pSMB->Timeout = 0;
5032 pSMB->Reserved2 = 0;
5033 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5034 offset = param_offset + params;
5035
Steve French50c2f752007-07-13 00:33:32 +00005036 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005037
Steve French26f57362007-08-30 22:09:15 +00005038 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005039 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005040 /* BB find max SMB PDU from sess */
5041 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005042 pSMB->SetupCount = 1;
5043 pSMB->Reserved3 = 0;
5044 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5045 byte_count = 3 /* pad */ + params + count;
5046 pSMB->DataCount = cpu_to_le16(count);
5047 pSMB->ParameterCount = cpu_to_le16(params);
5048 pSMB->TotalDataCount = pSMB->DataCount;
5049 pSMB->TotalParameterCount = pSMB->ParameterCount;
5050 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5051 pSMB->DataOffset = cpu_to_le16(offset);
5052 pSMB->Fid = fid;
5053 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5054 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5055 else
5056 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5057 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005058 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005059 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005060 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Steve French133672e2007-11-13 22:41:37 +00005061 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005062 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005063 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005064
Steve French50c2f752007-07-13 00:33:32 +00005065 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005066 since file handle passed in no longer valid */
5067
5068 return rc;
5069}
5070
Jeff Layton6d22f092008-09-23 11:48:35 -04005071int
5072CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon,
5073 bool delete_file, __u16 fid, __u32 pid_of_opener)
5074{
5075 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5076 char *data_offset;
5077 int rc = 0;
5078 __u16 params, param_offset, offset, byte_count, count;
5079
Joe Perchesb6b38f72010-04-21 03:50:45 +00005080 cFYI(1, "Set File Disposition (via SetFileInfo)");
Jeff Layton6d22f092008-09-23 11:48:35 -04005081 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5082
5083 if (rc)
5084 return rc;
5085
5086 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5087 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5088
5089 params = 6;
5090 pSMB->MaxSetupCount = 0;
5091 pSMB->Reserved = 0;
5092 pSMB->Flags = 0;
5093 pSMB->Timeout = 0;
5094 pSMB->Reserved2 = 0;
5095 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5096 offset = param_offset + params;
5097
5098 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5099
5100 count = 1;
5101 pSMB->MaxParameterCount = cpu_to_le16(2);
5102 /* BB find max SMB PDU from sess */
5103 pSMB->MaxDataCount = cpu_to_le16(1000);
5104 pSMB->SetupCount = 1;
5105 pSMB->Reserved3 = 0;
5106 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5107 byte_count = 3 /* pad */ + params + count;
5108 pSMB->DataCount = cpu_to_le16(count);
5109 pSMB->ParameterCount = cpu_to_le16(params);
5110 pSMB->TotalDataCount = pSMB->DataCount;
5111 pSMB->TotalParameterCount = pSMB->ParameterCount;
5112 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5113 pSMB->DataOffset = cpu_to_le16(offset);
5114 pSMB->Fid = fid;
5115 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5116 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005117 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton6d22f092008-09-23 11:48:35 -04005118 pSMB->ByteCount = cpu_to_le16(byte_count);
5119 *data_offset = delete_file ? 1 : 0;
5120 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
5121 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005122 cFYI(1, "Send error in SetFileDisposition = %d", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005123
5124 return rc;
5125}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005126
5127int
Jeff Layton6fc000e2008-08-02 07:26:12 -04005128CIFSSMBSetPathInfo(const int xid, struct cifsTconInfo *tcon,
5129 const char *fileName, const FILE_BASIC_INFO *data,
5130 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005131{
5132 TRANSACTION2_SPI_REQ *pSMB = NULL;
5133 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5134 int name_len;
5135 int rc = 0;
5136 int bytes_returned = 0;
5137 char *data_offset;
5138 __u16 params, param_offset, offset, byte_count, count;
5139
Joe Perchesb6b38f72010-04-21 03:50:45 +00005140 cFYI(1, "In SetTimes");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005141
5142SetTimesRetry:
5143 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5144 (void **) &pSMBr);
5145 if (rc)
5146 return rc;
5147
5148 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5149 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05005150 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005151 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005152 name_len++; /* trailing null */
5153 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005154 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005155 name_len = strnlen(fileName, PATH_MAX);
5156 name_len++; /* trailing null */
5157 strncpy(pSMB->FileName, fileName, name_len);
5158 }
5159
5160 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005161 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005162 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005163 /* BB find max SMB PDU from sess structure BB */
5164 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005165 pSMB->MaxSetupCount = 0;
5166 pSMB->Reserved = 0;
5167 pSMB->Flags = 0;
5168 pSMB->Timeout = 0;
5169 pSMB->Reserved2 = 0;
5170 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005171 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005172 offset = param_offset + params;
5173 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5174 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5175 pSMB->DataOffset = cpu_to_le16(offset);
5176 pSMB->SetupCount = 1;
5177 pSMB->Reserved3 = 0;
5178 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5179 byte_count = 3 /* pad */ + params + count;
5180
5181 pSMB->DataCount = cpu_to_le16(count);
5182 pSMB->ParameterCount = cpu_to_le16(params);
5183 pSMB->TotalDataCount = pSMB->DataCount;
5184 pSMB->TotalParameterCount = pSMB->ParameterCount;
5185 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5186 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5187 else
5188 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5189 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005190 inc_rfc1001_len(pSMB, byte_count);
Steve French26f57362007-08-30 22:09:15 +00005191 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005192 pSMB->ByteCount = cpu_to_le16(byte_count);
5193 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5194 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005195 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005196 cFYI(1, "SetPathInfo (times) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005197
5198 cifs_buf_release(pSMB);
5199
5200 if (rc == -EAGAIN)
5201 goto SetTimesRetry;
5202
5203 return rc;
5204}
5205
5206/* Can not be used to set time stamps yet (due to old DOS time format) */
5207/* Can be used to set attributes */
5208#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5209 handling it anyway and NT4 was what we thought it would be needed for
5210 Do not delete it until we prove whether needed for Win9x though */
5211int
5212CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
5213 __u16 dos_attrs, const struct nls_table *nls_codepage)
5214{
5215 SETATTR_REQ *pSMB = NULL;
5216 SETATTR_RSP *pSMBr = NULL;
5217 int rc = 0;
5218 int bytes_returned;
5219 int name_len;
5220
Joe Perchesb6b38f72010-04-21 03:50:45 +00005221 cFYI(1, "In SetAttrLegacy");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005222
5223SetAttrLgcyRetry:
5224 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5225 (void **) &pSMBr);
5226 if (rc)
5227 return rc;
5228
5229 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5230 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005231 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005232 PATH_MAX, nls_codepage);
5233 name_len++; /* trailing null */
5234 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005235 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005236 name_len = strnlen(fileName, PATH_MAX);
5237 name_len++; /* trailing null */
5238 strncpy(pSMB->fileName, fileName, name_len);
5239 }
5240 pSMB->attr = cpu_to_le16(dos_attrs);
5241 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005242 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005243 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5244 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5245 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005246 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005247 cFYI(1, "Error in LegacySetAttr = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005248
5249 cifs_buf_release(pSMB);
5250
5251 if (rc == -EAGAIN)
5252 goto SetAttrLgcyRetry;
5253
5254 return rc;
5255}
5256#endif /* temporarily unneeded SetAttr legacy function */
5257
Jeff Layton654cf142009-07-09 20:02:49 -04005258static void
5259cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5260 const struct cifs_unix_set_info_args *args)
5261{
5262 u64 mode = args->mode;
5263
5264 /*
5265 * Samba server ignores set of file size to zero due to bugs in some
5266 * older clients, but we should be precise - we use SetFileSize to
5267 * set file size and do not want to truncate file size to zero
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005268 * accidentally as happened on one Samba server beta by putting
Jeff Layton654cf142009-07-09 20:02:49 -04005269 * zero instead of -1 here
5270 */
5271 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5272 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5273 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5274 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5275 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5276 data_offset->Uid = cpu_to_le64(args->uid);
5277 data_offset->Gid = cpu_to_le64(args->gid);
5278 /* better to leave device as zero when it is */
5279 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5280 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5281 data_offset->Permissions = cpu_to_le64(mode);
5282
5283 if (S_ISREG(mode))
5284 data_offset->Type = cpu_to_le32(UNIX_FILE);
5285 else if (S_ISDIR(mode))
5286 data_offset->Type = cpu_to_le32(UNIX_DIR);
5287 else if (S_ISLNK(mode))
5288 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5289 else if (S_ISCHR(mode))
5290 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5291 else if (S_ISBLK(mode))
5292 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5293 else if (S_ISFIFO(mode))
5294 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5295 else if (S_ISSOCK(mode))
5296 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5297}
5298
Linus Torvalds1da177e2005-04-16 15:20:36 -07005299int
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005300CIFSSMBUnixSetFileInfo(const int xid, struct cifsTconInfo *tcon,
5301 const struct cifs_unix_set_info_args *args,
5302 u16 fid, u32 pid_of_opener)
5303{
5304 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5305 FILE_UNIX_BASIC_INFO *data_offset;
5306 int rc = 0;
5307 u16 params, param_offset, offset, byte_count, count;
5308
Joe Perchesb6b38f72010-04-21 03:50:45 +00005309 cFYI(1, "Set Unix Info (via SetFileInfo)");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005310 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5311
5312 if (rc)
5313 return rc;
5314
5315 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5316 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5317
5318 params = 6;
5319 pSMB->MaxSetupCount = 0;
5320 pSMB->Reserved = 0;
5321 pSMB->Flags = 0;
5322 pSMB->Timeout = 0;
5323 pSMB->Reserved2 = 0;
5324 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5325 offset = param_offset + params;
5326
5327 data_offset = (FILE_UNIX_BASIC_INFO *)
5328 ((char *)(&pSMB->hdr.Protocol) + offset);
5329 count = sizeof(FILE_UNIX_BASIC_INFO);
5330
5331 pSMB->MaxParameterCount = cpu_to_le16(2);
5332 /* BB find max SMB PDU from sess */
5333 pSMB->MaxDataCount = cpu_to_le16(1000);
5334 pSMB->SetupCount = 1;
5335 pSMB->Reserved3 = 0;
5336 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5337 byte_count = 3 /* pad */ + params + count;
5338 pSMB->DataCount = cpu_to_le16(count);
5339 pSMB->ParameterCount = cpu_to_le16(params);
5340 pSMB->TotalDataCount = pSMB->DataCount;
5341 pSMB->TotalParameterCount = pSMB->ParameterCount;
5342 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5343 pSMB->DataOffset = cpu_to_le16(offset);
5344 pSMB->Fid = fid;
5345 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5346 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005347 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005348 pSMB->ByteCount = cpu_to_le16(byte_count);
5349
5350 cifs_fill_unix_set_info(data_offset, args);
5351
5352 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
5353 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005354 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005355
5356 /* Note: On -EAGAIN error only caller can retry on handle based calls
5357 since file handle passed in no longer valid */
5358
5359 return rc;
5360}
5361
5362int
Jeff Layton01ea95e2009-07-09 20:02:49 -04005363CIFSSMBUnixSetPathInfo(const int xid, struct cifsTconInfo *tcon, char *fileName,
5364 const struct cifs_unix_set_info_args *args,
5365 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005366{
5367 TRANSACTION2_SPI_REQ *pSMB = NULL;
5368 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5369 int name_len;
5370 int rc = 0;
5371 int bytes_returned = 0;
5372 FILE_UNIX_BASIC_INFO *data_offset;
5373 __u16 params, param_offset, offset, count, byte_count;
5374
Joe Perchesb6b38f72010-04-21 03:50:45 +00005375 cFYI(1, "In SetUID/GID/Mode");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005376setPermsRetry:
5377 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5378 (void **) &pSMBr);
5379 if (rc)
5380 return rc;
5381
5382 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5383 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005384 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005385 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005386 name_len++; /* trailing null */
5387 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005388 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005389 name_len = strnlen(fileName, PATH_MAX);
5390 name_len++; /* trailing null */
5391 strncpy(pSMB->FileName, fileName, name_len);
5392 }
5393
5394 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005395 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005396 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005397 /* BB find max SMB PDU from sess structure BB */
5398 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005399 pSMB->MaxSetupCount = 0;
5400 pSMB->Reserved = 0;
5401 pSMB->Flags = 0;
5402 pSMB->Timeout = 0;
5403 pSMB->Reserved2 = 0;
5404 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005405 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005406 offset = param_offset + params;
5407 data_offset =
5408 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5409 offset);
5410 memset(data_offset, 0, count);
5411 pSMB->DataOffset = cpu_to_le16(offset);
5412 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5413 pSMB->SetupCount = 1;
5414 pSMB->Reserved3 = 0;
5415 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5416 byte_count = 3 /* pad */ + params + count;
5417 pSMB->ParameterCount = cpu_to_le16(params);
5418 pSMB->DataCount = cpu_to_le16(count);
5419 pSMB->TotalParameterCount = pSMB->ParameterCount;
5420 pSMB->TotalDataCount = pSMB->DataCount;
5421 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5422 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005423 inc_rfc1001_len(pSMB, byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005424
Jeff Layton654cf142009-07-09 20:02:49 -04005425 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005426
5427 pSMB->ByteCount = cpu_to_le16(byte_count);
5428 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5429 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005430 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005431 cFYI(1, "SetPathInfo (perms) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005432
Steve French0d817bc2008-05-22 02:02:03 +00005433 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005434 if (rc == -EAGAIN)
5435 goto setPermsRetry;
5436 return rc;
5437}
5438
Linus Torvalds1da177e2005-04-16 15:20:36 -07005439#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05005440/*
5441 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
5442 * function used by listxattr and getxattr type calls. When ea_name is set,
5443 * it looks for that attribute name and stuffs that value into the EAData
5444 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
5445 * buffer. In both cases, the return value is either the length of the
5446 * resulting data or a negative error code. If EAData is a NULL pointer then
5447 * the data isn't copied to it, but the length is returned.
5448 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005449ssize_t
5450CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05005451 const unsigned char *searchName, const unsigned char *ea_name,
5452 char *EAData, size_t buf_size,
5453 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005454{
5455 /* BB assumes one setup word */
5456 TRANSACTION2_QPI_REQ *pSMB = NULL;
5457 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5458 int rc = 0;
5459 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05005460 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005461 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00005462 struct fea *temp_fea;
5463 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05005464 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005465 __u16 params, byte_count, data_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005466
Joe Perchesb6b38f72010-04-21 03:50:45 +00005467 cFYI(1, "In Query All EAs path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005468QAllEAsRetry:
5469 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5470 (void **) &pSMBr);
5471 if (rc)
5472 return rc;
5473
5474 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05005475 list_len =
Steve French50c2f752007-07-13 00:33:32 +00005476 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005477 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05005478 list_len++; /* trailing null */
5479 list_len *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005480 } else { /* BB improve the check for buffer overruns BB */
Jeff Layton6e462b92010-02-10 16:18:26 -05005481 list_len = strnlen(searchName, PATH_MAX);
5482 list_len++; /* trailing null */
5483 strncpy(pSMB->FileName, searchName, list_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005484 }
5485
Jeff Layton6e462b92010-02-10 16:18:26 -05005486 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005487 pSMB->TotalDataCount = 0;
5488 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005489 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05005490 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005491 pSMB->MaxSetupCount = 0;
5492 pSMB->Reserved = 0;
5493 pSMB->Flags = 0;
5494 pSMB->Timeout = 0;
5495 pSMB->Reserved2 = 0;
5496 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005497 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005498 pSMB->DataCount = 0;
5499 pSMB->DataOffset = 0;
5500 pSMB->SetupCount = 1;
5501 pSMB->Reserved3 = 0;
5502 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5503 byte_count = params + 1 /* pad */ ;
5504 pSMB->TotalParameterCount = cpu_to_le16(params);
5505 pSMB->ParameterCount = pSMB->TotalParameterCount;
5506 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5507 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005508 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005509 pSMB->ByteCount = cpu_to_le16(byte_count);
5510
5511 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5512 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5513 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005514 cFYI(1, "Send error in QueryAllEAs = %d", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05005515 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005516 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05005517
5518
5519 /* BB also check enough total bytes returned */
5520 /* BB we need to improve the validity checking
5521 of these trans2 responses */
5522
5523 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Jeff Layton820a8032011-05-04 08:05:26 -04005524 if (rc || get_bcc(&pSMBr->hdr) < 4) {
Jeff Laytonf0d38682010-02-10 16:18:26 -05005525 rc = -EIO; /* bad smb */
5526 goto QAllEAsOut;
5527 }
5528
5529 /* check that length of list is not more than bcc */
5530 /* check that each entry does not go beyond length
5531 of list */
5532 /* check that each element of each entry does not
5533 go beyond end of list */
5534 /* validate_trans2_offsets() */
5535 /* BB check if start of smb + data_offset > &bcc+ bcc */
5536
5537 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5538 ea_response_data = (struct fealist *)
5539 (((char *) &pSMBr->hdr.Protocol) + data_offset);
5540
Jeff Layton6e462b92010-02-10 16:18:26 -05005541 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesb6b38f72010-04-21 03:50:45 +00005542 cFYI(1, "ea length %d", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05005543 if (list_len <= 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005544 cFYI(1, "empty EA list returned from server");
Jeff Laytonf0d38682010-02-10 16:18:26 -05005545 goto QAllEAsOut;
5546 }
5547
Jeff Layton0cd126b2010-02-10 16:18:26 -05005548 /* make sure list_len doesn't go past end of SMB */
Jeff Layton690c5222011-01-20 13:36:51 -05005549 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
Jeff Layton0cd126b2010-02-10 16:18:26 -05005550 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005551 cFYI(1, "EA list appears to go beyond SMB");
Jeff Layton0cd126b2010-02-10 16:18:26 -05005552 rc = -EIO;
5553 goto QAllEAsOut;
5554 }
5555
Jeff Laytonf0d38682010-02-10 16:18:26 -05005556 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05005557 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005558 temp_fea = ea_response_data->list;
5559 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05005560 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00005561 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005562 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05005563
Jeff Layton6e462b92010-02-10 16:18:26 -05005564 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005565 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05005566 /* make sure we can read name_len and value_len */
5567 if (list_len < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005568 cFYI(1, "EA entry goes beyond length of list");
Jeff Layton0cd126b2010-02-10 16:18:26 -05005569 rc = -EIO;
5570 goto QAllEAsOut;
5571 }
5572
5573 name_len = temp_fea->name_len;
5574 value_len = le16_to_cpu(temp_fea->value_len);
5575 list_len -= name_len + 1 + value_len;
5576 if (list_len < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005577 cFYI(1, "EA entry goes beyond length of list");
Jeff Layton0cd126b2010-02-10 16:18:26 -05005578 rc = -EIO;
5579 goto QAllEAsOut;
5580 }
5581
Jeff Layton31c05192010-02-10 16:18:26 -05005582 if (ea_name) {
5583 if (strncmp(ea_name, temp_ptr, name_len) == 0) {
5584 temp_ptr += name_len + 1;
5585 rc = value_len;
5586 if (buf_size == 0)
5587 goto QAllEAsOut;
5588 if ((size_t)value_len > buf_size) {
5589 rc = -ERANGE;
5590 goto QAllEAsOut;
5591 }
5592 memcpy(EAData, temp_ptr, value_len);
5593 goto QAllEAsOut;
5594 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05005595 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05005596 /* account for prefix user. and trailing null */
5597 rc += (5 + 1 + name_len);
5598 if (rc < (int) buf_size) {
5599 memcpy(EAData, "user.", 5);
5600 EAData += 5;
5601 memcpy(EAData, temp_ptr, name_len);
5602 EAData += name_len;
5603 /* null terminate name */
5604 *EAData = 0;
5605 ++EAData;
5606 } else if (buf_size == 0) {
5607 /* skip copy - calc size only */
5608 } else {
5609 /* stop before overrun buffer */
5610 rc = -ERANGE;
5611 break;
5612 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05005613 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05005614 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005615 temp_fea = (struct fea *)temp_ptr;
5616 }
5617
Jeff Layton31c05192010-02-10 16:18:26 -05005618 /* didn't find the named attribute */
5619 if (ea_name)
5620 rc = -ENODATA;
5621
Jeff Laytonf0d38682010-02-10 16:18:26 -05005622QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00005623 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005624 if (rc == -EAGAIN)
5625 goto QAllEAsRetry;
5626
5627 return (ssize_t)rc;
5628}
5629
Linus Torvalds1da177e2005-04-16 15:20:36 -07005630int
5631CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00005632 const char *ea_name, const void *ea_value,
5633 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5634 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005635{
5636 struct smb_com_transaction2_spi_req *pSMB = NULL;
5637 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5638 struct fealist *parm_data;
5639 int name_len;
5640 int rc = 0;
5641 int bytes_returned = 0;
5642 __u16 params, param_offset, byte_count, offset, count;
5643
Joe Perchesb6b38f72010-04-21 03:50:45 +00005644 cFYI(1, "In SetEA");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005645SetEARetry:
5646 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5647 (void **) &pSMBr);
5648 if (rc)
5649 return rc;
5650
5651 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5652 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005653 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005654 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005655 name_len++; /* trailing null */
5656 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005657 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005658 name_len = strnlen(fileName, PATH_MAX);
5659 name_len++; /* trailing null */
5660 strncpy(pSMB->FileName, fileName, name_len);
5661 }
5662
5663 params = 6 + name_len;
5664
5665 /* done calculating parms using name_len of file name,
5666 now use name_len to calculate length of ea name
5667 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00005668 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005669 name_len = 0;
5670 else
Steve French50c2f752007-07-13 00:33:32 +00005671 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005672
Steve Frenchdae5dbd2007-12-30 23:49:57 +00005673 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005674 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005675 /* BB find max SMB PDU from sess */
5676 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005677 pSMB->MaxSetupCount = 0;
5678 pSMB->Reserved = 0;
5679 pSMB->Flags = 0;
5680 pSMB->Timeout = 0;
5681 pSMB->Reserved2 = 0;
5682 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005683 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005684 offset = param_offset + params;
5685 pSMB->InformationLevel =
5686 cpu_to_le16(SMB_SET_FILE_EA);
5687
5688 parm_data =
5689 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5690 offset);
5691 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5692 pSMB->DataOffset = cpu_to_le16(offset);
5693 pSMB->SetupCount = 1;
5694 pSMB->Reserved3 = 0;
5695 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5696 byte_count = 3 /* pad */ + params + count;
5697 pSMB->DataCount = cpu_to_le16(count);
5698 parm_data->list_len = cpu_to_le32(count);
5699 parm_data->list[0].EA_flags = 0;
5700 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08005701 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005702 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00005703 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00005704 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005705 parm_data->list[0].name[name_len] = 0;
5706 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5707 /* caller ensures that ea_value_len is less than 64K but
5708 we need to ensure that it fits within the smb */
5709
Steve French50c2f752007-07-13 00:33:32 +00005710 /*BB add length check to see if it would fit in
5711 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00005712 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5713 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00005714 memcpy(parm_data->list[0].name+name_len+1,
5715 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005716
5717 pSMB->TotalDataCount = pSMB->DataCount;
5718 pSMB->ParameterCount = cpu_to_le16(params);
5719 pSMB->TotalParameterCount = pSMB->ParameterCount;
5720 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005721 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005722 pSMB->ByteCount = cpu_to_le16(byte_count);
5723 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5724 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005725 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005726 cFYI(1, "SetPathInfo (EA) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005727
5728 cifs_buf_release(pSMB);
5729
5730 if (rc == -EAGAIN)
5731 goto SetEARetry;
5732
5733 return rc;
5734}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005735#endif
Steve French0eff0e22011-02-24 05:39:23 +00005736
5737#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */
5738/*
5739 * Years ago the kernel added a "dnotify" function for Samba server,
5740 * to allow network clients (such as Windows) to display updated
5741 * lists of files in directory listings automatically when
5742 * files are added by one user when another user has the
5743 * same directory open on their desktop. The Linux cifs kernel
5744 * client hooked into the kernel side of this interface for
5745 * the same reason, but ironically when the VFS moved from
5746 * "dnotify" to "inotify" it became harder to plug in Linux
5747 * network file system clients (the most obvious use case
5748 * for notify interfaces is when multiple users can update
5749 * the contents of the same directory - exactly what network
5750 * file systems can do) although the server (Samba) could
5751 * still use it. For the short term we leave the worker
5752 * function ifdeffed out (below) until inotify is fixed
5753 * in the VFS to make it easier to plug in network file
5754 * system clients. If inotify turns out to be permanently
5755 * incompatible for network fs clients, we could instead simply
5756 * expose this config flag by adding a future cifs (and smb2) notify ioctl.
5757 */
5758int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
5759 const int notify_subdirs, const __u16 netfid,
5760 __u32 filter, struct file *pfile, int multishot,
5761 const struct nls_table *nls_codepage)
5762{
5763 int rc = 0;
5764 struct smb_com_transaction_change_notify_req *pSMB = NULL;
5765 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
5766 struct dir_notify_req *dnotify_req;
5767 int bytes_returned;
5768
5769 cFYI(1, "In CIFSSMBNotify for file handle %d", (int)netfid);
5770 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
5771 (void **) &pSMBr);
5772 if (rc)
5773 return rc;
5774
5775 pSMB->TotalParameterCount = 0 ;
5776 pSMB->TotalDataCount = 0;
5777 pSMB->MaxParameterCount = cpu_to_le32(2);
5778 /* BB find exact data count max from sess structure BB */
5779 pSMB->MaxDataCount = 0; /* same in little endian or be */
5780/* BB VERIFY verify which is correct for above BB */
5781 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
5782 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
5783
5784 pSMB->MaxSetupCount = 4;
5785 pSMB->Reserved = 0;
5786 pSMB->ParameterOffset = 0;
5787 pSMB->DataCount = 0;
5788 pSMB->DataOffset = 0;
5789 pSMB->SetupCount = 4; /* single byte does not need le conversion */
5790 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
5791 pSMB->ParameterCount = pSMB->TotalParameterCount;
5792 if (notify_subdirs)
5793 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
5794 pSMB->Reserved2 = 0;
5795 pSMB->CompletionFilter = cpu_to_le32(filter);
5796 pSMB->Fid = netfid; /* file handle always le */
5797 pSMB->ByteCount = 0;
5798
5799 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5800 (struct smb_hdr *)pSMBr, &bytes_returned,
5801 CIFS_ASYNC_OP);
5802 if (rc) {
5803 cFYI(1, "Error in Notify = %d", rc);
5804 } else {
5805 /* Add file to outstanding requests */
5806 /* BB change to kmem cache alloc */
5807 dnotify_req = kmalloc(
5808 sizeof(struct dir_notify_req),
5809 GFP_KERNEL);
5810 if (dnotify_req) {
5811 dnotify_req->Pid = pSMB->hdr.Pid;
5812 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
5813 dnotify_req->Mid = pSMB->hdr.Mid;
5814 dnotify_req->Tid = pSMB->hdr.Tid;
5815 dnotify_req->Uid = pSMB->hdr.Uid;
5816 dnotify_req->netfid = netfid;
5817 dnotify_req->pfile = pfile;
5818 dnotify_req->filter = filter;
5819 dnotify_req->multishot = multishot;
5820 spin_lock(&GlobalMid_Lock);
5821 list_add_tail(&dnotify_req->lhead,
5822 &GlobalDnotifyReqList);
5823 spin_unlock(&GlobalMid_Lock);
5824 } else
5825 rc = -ENOMEM;
5826 }
5827 cifs_buf_release(pSMB);
5828 return rc;
5829}
5830#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */