blob: 54b9f5d8d1dbf94a422d212039b45ea3862c5098 [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
139 if (ses->status == CifsExiting)
140 return -EIO;
141
142 /*
143 * Give demultiplex thread up to 10 seconds to reconnect, should be
144 * greater than cifs socket timeout which is 7 seconds
145 */
146 while (server->tcpStatus == CifsNeedReconnect) {
147 wait_event_interruptible_timeout(server->response_q,
148 (server->tcpStatus == CifsGood), 10 * HZ);
149
150 /* is TCP session is reestablished now ?*/
151 if (server->tcpStatus != CifsNeedReconnect)
152 break;
153
154 /*
155 * on "soft" mounts we wait once. Hard mounts keep
156 * retrying until process is killed or server comes
157 * back on-line
158 */
159 if (!tcon->retry || ses->status == CifsExiting) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000160 cFYI(1, "gave up waiting on reconnect in smb_init");
Jeff Layton9162ab22009-09-03 12:07:17 -0400161 return -EHOSTDOWN;
162 }
163 }
164
165 if (!ses->need_reconnect && !tcon->need_reconnect)
166 return 0;
167
168 nls_codepage = load_nls_default();
169
170 /*
171 * need to prevent multiple threads trying to simultaneously
172 * reconnect the same SMB session
173 */
Steve Frenchd7b619c2010-02-25 05:36:46 +0000174 mutex_lock(&ses->session_mutex);
Jeff Layton198b5682010-04-24 07:57:48 -0400175 rc = cifs_negotiate_protocol(0, ses);
176 if (rc == 0 && ses->need_reconnect)
Jeff Layton9162ab22009-09-03 12:07:17 -0400177 rc = cifs_setup_session(0, ses, nls_codepage);
178
179 /* do we need to reconnect tcon? */
180 if (rc || !tcon->need_reconnect) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000181 mutex_unlock(&ses->session_mutex);
Jeff Layton9162ab22009-09-03 12:07:17 -0400182 goto out;
183 }
184
185 mark_open_files_invalid(tcon);
186 rc = CIFSTCon(0, ses, tcon->treeName, tcon, nls_codepage);
Steve Frenchd7b619c2010-02-25 05:36:46 +0000187 mutex_unlock(&ses->session_mutex);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000188 cFYI(1, "reconnect tcon rc = %d", rc);
Jeff Layton9162ab22009-09-03 12:07:17 -0400189
190 if (rc)
191 goto out;
192
193 /*
194 * FIXME: check if wsize needs updated due to negotiated smb buffer
195 * size shrinking
196 */
197 atomic_inc(&tconInfoReconnectCount);
198
199 /* tell server Unix caps we support */
200 if (ses->capabilities & CAP_UNIX)
201 reset_cifs_unix_caps(0, tcon, NULL, NULL);
202
203 /*
204 * Removed call to reopen open files here. It is safer (and faster) to
205 * reopen files one at a time as needed in read and write.
206 *
207 * FIXME: what about file locks? don't we need to reclaim them ASAP?
208 */
209
210out:
211 /*
212 * Check if handle based operation so we know whether we can continue
213 * or not without returning to caller to reset file handle
214 */
215 switch (smb_command) {
216 case SMB_COM_READ_ANDX:
217 case SMB_COM_WRITE_ANDX:
218 case SMB_COM_CLOSE:
219 case SMB_COM_FIND_CLOSE2:
220 case SMB_COM_LOCKING_ANDX:
221 rc = -EAGAIN;
222 }
223
224 unload_nls(nls_codepage);
225 return rc;
226}
227
Steve Frenchad7a2922008-02-07 23:25:02 +0000228/* Allocate and return pointer to an SMB request buffer, and set basic
229 SMB information in the SMB header. If the return code is zero, this
230 function must have filled in request_buf pointer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231static int
232small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000233 void **request_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234{
Jeff Laytonf5695992010-09-29 15:27:08 -0400235 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236
Jeff Layton9162ab22009-09-03 12:07:17 -0400237 rc = cifs_reconnect_tcon(tcon, smb_command);
Steve French790fe572007-07-07 19:25:05 +0000238 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239 return rc;
240
241 *request_buf = cifs_small_buf_get();
242 if (*request_buf == NULL) {
243 /* BB should we add a retry in here if not a writepage? */
244 return -ENOMEM;
245 }
246
Steve French63135e02007-07-17 17:34:02 +0000247 header_assemble((struct smb_hdr *) *request_buf, smb_command,
Steve Frenchc18c8422007-07-18 23:21:09 +0000248 tcon, wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249
Steve French790fe572007-07-07 19:25:05 +0000250 if (tcon != NULL)
251 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700252
Jeff Laytonf5695992010-09-29 15:27:08 -0400253 return 0;
Steve French5815449d2006-02-14 01:36:20 +0000254}
255
Steve French12b3b8f2006-02-09 21:12:47 +0000256int
Steve French50c2f752007-07-13 00:33:32 +0000257small_smb_init_no_tc(const int smb_command, const int wct,
Steve French5815449d2006-02-14 01:36:20 +0000258 struct cifsSesInfo *ses, void **request_buf)
Steve French12b3b8f2006-02-09 21:12:47 +0000259{
260 int rc;
Steve French50c2f752007-07-13 00:33:32 +0000261 struct smb_hdr *buffer;
Steve French12b3b8f2006-02-09 21:12:47 +0000262
Steve French5815449d2006-02-14 01:36:20 +0000263 rc = small_smb_init(smb_command, wct, NULL, request_buf);
Steve French790fe572007-07-07 19:25:05 +0000264 if (rc)
Steve French12b3b8f2006-02-09 21:12:47 +0000265 return rc;
266
Steve French04fdabe2006-02-10 05:52:50 +0000267 buffer = (struct smb_hdr *)*request_buf;
Steve French12b3b8f2006-02-09 21:12:47 +0000268 buffer->Mid = GetNextMid(ses->server);
269 if (ses->capabilities & CAP_UNICODE)
270 buffer->Flags2 |= SMBFLG2_UNICODE;
Steve French04fdabe2006-02-10 05:52:50 +0000271 if (ses->capabilities & CAP_STATUS32)
Steve French12b3b8f2006-02-09 21:12:47 +0000272 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
273
274 /* uid, tid can stay at zero as set in header assemble */
275
Steve French50c2f752007-07-13 00:33:32 +0000276 /* BB add support for turning on the signing when
Steve French12b3b8f2006-02-09 21:12:47 +0000277 this function is used after 1st of session setup requests */
278
279 return rc;
280}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281
282/* If the return code is zero, this function must fill in request_buf pointer */
283static int
Jeff Laytonf5695992010-09-29 15:27:08 -0400284__smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
285 void **request_buf, void **response_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287 *request_buf = cifs_buf_get();
288 if (*request_buf == NULL) {
289 /* BB should we add a retry in here if not a writepage? */
290 return -ENOMEM;
291 }
292 /* Although the original thought was we needed the response buf for */
293 /* potential retries of smb operations it turns out we can determine */
294 /* from the mid flags when the request buffer can be resent without */
295 /* having to use a second distinct buffer for the response */
Steve French790fe572007-07-07 19:25:05 +0000296 if (response_buf)
Steve French50c2f752007-07-13 00:33:32 +0000297 *response_buf = *request_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298
299 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000300 wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301
Steve French790fe572007-07-07 19:25:05 +0000302 if (tcon != NULL)
303 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700304
Jeff Laytonf5695992010-09-29 15:27:08 -0400305 return 0;
306}
307
308/* If the return code is zero, this function must fill in request_buf pointer */
309static int
310smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
311 void **request_buf, void **response_buf)
312{
313 int rc;
314
315 rc = cifs_reconnect_tcon(tcon, smb_command);
316 if (rc)
317 return rc;
318
319 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
320}
321
322static int
323smb_init_no_reconnect(int smb_command, int wct, struct cifsTconInfo *tcon,
324 void **request_buf, void **response_buf)
325{
326 if (tcon->ses->need_reconnect || tcon->need_reconnect)
327 return -EHOSTDOWN;
328
329 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330}
331
Steve French50c2f752007-07-13 00:33:32 +0000332static int validate_t2(struct smb_t2_rsp *pSMB)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333{
334 int rc = -EINVAL;
335 int total_size;
Steve French50c2f752007-07-13 00:33:32 +0000336 char *pBCC;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337
338 /* check for plausible wct, bcc and t2 data and parm sizes */
339 /* check for parm and data offset going beyond end of smb */
Steve French790fe572007-07-07 19:25:05 +0000340 if (pSMB->hdr.WordCount >= 10) {
341 if ((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342 (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
343 /* check that bcc is at least as big as parms + data */
344 /* check that bcc is less than negotiated smb buffer */
345 total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
Steve French790fe572007-07-07 19:25:05 +0000346 if (total_size < 512) {
Steve Frenchc18c8422007-07-18 23:21:09 +0000347 total_size +=
Steve French63135e02007-07-17 17:34:02 +0000348 le16_to_cpu(pSMB->t2_rsp.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 /* BCC le converted in SendReceive */
Steve French50c2f752007-07-13 00:33:32 +0000350 pBCC = (pSMB->hdr.WordCount * 2) +
Steve French09d1db52005-04-28 22:41:08 -0700351 sizeof(struct smb_hdr) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 (char *)pSMB;
Steve French790fe572007-07-07 19:25:05 +0000353 if ((total_size <= (*(u16 *)pBCC)) &&
Steve French50c2f752007-07-13 00:33:32 +0000354 (total_size <
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
356 return 0;
357 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 }
359 }
360 }
Steve French50c2f752007-07-13 00:33:32 +0000361 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 sizeof(struct smb_t2_rsp) + 16);
363 return rc;
364}
365int
366CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
367{
368 NEGOTIATE_REQ *pSMB;
369 NEGOTIATE_RSP *pSMBr;
370 int rc = 0;
371 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000372 int i;
Steve French50c2f752007-07-13 00:33:32 +0000373 struct TCP_Server_Info *server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374 u16 count;
Steve French750d1152006-06-27 06:28:30 +0000375 unsigned int secFlags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376
Steve French790fe572007-07-07 19:25:05 +0000377 if (ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 server = ses->server;
379 else {
380 rc = -EIO;
381 return rc;
382 }
383 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
384 (void **) &pSMB, (void **) &pSMBr);
385 if (rc)
386 return rc;
Steve French750d1152006-06-27 06:28:30 +0000387
388 /* if any of auth flags (ie not sign or seal) are overriden use them */
Steve French790fe572007-07-07 19:25:05 +0000389 if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
Steve French762e5ab2007-06-28 18:41:42 +0000390 secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
Steve French750d1152006-06-27 06:28:30 +0000391 else /* if override flags set only sign/seal OR them with global auth */
Jeff Layton04912d62010-04-24 07:57:45 -0400392 secFlags = global_secflags | ses->overrideSecFlg;
Steve French750d1152006-06-27 06:28:30 +0000393
Joe Perchesb6b38f72010-04-21 03:50:45 +0000394 cFYI(1, "secFlags 0x%x", secFlags);
Steve Frenchf40c5622006-06-28 00:13:38 +0000395
Steve French1982c342005-08-17 12:38:22 -0700396 pSMB->hdr.Mid = GetNextMid(server);
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000397 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
Steve Frencha0136892007-10-04 20:05:09 +0000398
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000399 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
Steve French254e55e2006-06-04 05:53:15 +0000400 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Steve Frencha0136892007-10-04 20:05:09 +0000401 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000402 cFYI(1, "Kerberos only mechanism, enable extended security");
Steve Frencha0136892007-10-04 20:05:09 +0000403 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Jeff Laytonb4d6fcf2011-01-07 11:30:28 -0500404 } else if ((secFlags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP)
Steve Frenchac683922009-05-06 04:16:04 +0000405 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
406 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_NTLMSSP) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000407 cFYI(1, "NTLMSSP only mechanism, enable extended security");
Steve Frenchac683922009-05-06 04:16:04 +0000408 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
409 }
Steve French50c2f752007-07-13 00:33:32 +0000410
Steve French39798772006-05-31 22:40:51 +0000411 count = 0;
Steve French50c2f752007-07-13 00:33:32 +0000412 for (i = 0; i < CIFS_NUM_PROT; i++) {
Steve French39798772006-05-31 22:40:51 +0000413 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
414 count += strlen(protocols[i].name) + 1;
415 /* null at end of source and target buffers anyway */
416 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 pSMB->hdr.smb_buf_length += count;
418 pSMB->ByteCount = cpu_to_le16(count);
419
420 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
421 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French50c2f752007-07-13 00:33:32 +0000422 if (rc != 0)
Steve French254e55e2006-06-04 05:53:15 +0000423 goto neg_err_exit;
424
Jeff Layton9bf67e52010-04-24 07:57:46 -0400425 server->dialect = le16_to_cpu(pSMBr->DialectIndex);
426 cFYI(1, "Dialect: %d", server->dialect);
Steve French254e55e2006-06-04 05:53:15 +0000427 /* Check wct = 1 error case */
Jeff Layton9bf67e52010-04-24 07:57:46 -0400428 if ((pSMBr->hdr.WordCount < 13) || (server->dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000429 /* core returns wct = 1, but we do not ask for core - otherwise
Steve French50c2f752007-07-13 00:33:32 +0000430 small wct just comes when dialect index is -1 indicating we
Steve French254e55e2006-06-04 05:53:15 +0000431 could not negotiate a common dialect */
432 rc = -EOPNOTSUPP;
433 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000434#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French790fe572007-07-07 19:25:05 +0000435 } else if ((pSMBr->hdr.WordCount == 13)
Jeff Layton9bf67e52010-04-24 07:57:46 -0400436 && ((server->dialect == LANMAN_PROT)
437 || (server->dialect == LANMAN2_PROT))) {
Steve Frenchb815f1e52006-10-02 05:53:29 +0000438 __s16 tmp;
Steve French50c2f752007-07-13 00:33:32 +0000439 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
Steve French254e55e2006-06-04 05:53:15 +0000440
Steve French790fe572007-07-07 19:25:05 +0000441 if ((secFlags & CIFSSEC_MAY_LANMAN) ||
Steve French750d1152006-06-27 06:28:30 +0000442 (secFlags & CIFSSEC_MAY_PLNTXT))
Steve French254e55e2006-06-04 05:53:15 +0000443 server->secType = LANMAN;
444 else {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000445 cERROR(1, "mount failed weak security disabled"
446 " in /proc/fs/cifs/SecurityFlags");
Steve French39798772006-05-31 22:40:51 +0000447 rc = -EOPNOTSUPP;
448 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000449 }
Steve French254e55e2006-06-04 05:53:15 +0000450 server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
451 server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
452 server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
Steve French39798772006-05-31 22:40:51 +0000453 (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve Frencheca6acf2009-02-20 05:43:09 +0000454 server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
Steve French254e55e2006-06-04 05:53:15 +0000455 GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
456 /* even though we do not use raw we might as well set this
457 accurately, in case we ever find a need for it */
Steve French790fe572007-07-07 19:25:05 +0000458 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
Steve Frencheca6acf2009-02-20 05:43:09 +0000459 server->max_rw = 0xFF00;
Steve French254e55e2006-06-04 05:53:15 +0000460 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
461 } else {
Steve Frencheca6acf2009-02-20 05:43:09 +0000462 server->max_rw = 0;/* do not need to use raw anyway */
Steve French254e55e2006-06-04 05:53:15 +0000463 server->capabilities = CAP_MPX_MODE;
464 }
Steve Frenchb815f1e52006-10-02 05:53:29 +0000465 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
Steve French1a70d652006-10-02 05:59:18 +0000466 if (tmp == -1) {
Steve French25ee4a92006-09-30 00:54:23 +0000467 /* OS/2 often does not set timezone therefore
468 * we must use server time to calc time zone.
Steve Frenchb815f1e52006-10-02 05:53:29 +0000469 * Could deviate slightly from the right zone.
470 * Smallest defined timezone difference is 15 minutes
471 * (i.e. Nepal). Rounding up/down is done to match
472 * this requirement.
Steve French25ee4a92006-09-30 00:54:23 +0000473 */
Steve Frenchb815f1e52006-10-02 05:53:29 +0000474 int val, seconds, remain, result;
Steve French25ee4a92006-09-30 00:54:23 +0000475 struct timespec ts, utc;
476 utc = CURRENT_TIME;
Jeff Laytonc4a2c082009-05-27 09:37:33 -0400477 ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
478 rsp->SrvTime.Time, 0);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000479 cFYI(1, "SrvTime %d sec since 1970 (utc: %d) diff: %d",
Steve French50c2f752007-07-13 00:33:32 +0000480 (int)ts.tv_sec, (int)utc.tv_sec,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000481 (int)(utc.tv_sec - ts.tv_sec));
Steve Frenchb815f1e52006-10-02 05:53:29 +0000482 val = (int)(utc.tv_sec - ts.tv_sec);
Andre Haupt8594c152007-08-30 20:18:41 +0000483 seconds = abs(val);
Steve French947a5062006-10-02 05:55:25 +0000484 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
Steve Frenchb815f1e52006-10-02 05:53:29 +0000485 remain = seconds % MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000486 if (remain >= (MIN_TZ_ADJ / 2))
Steve Frenchb815f1e52006-10-02 05:53:29 +0000487 result += MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000488 if (val < 0)
Steve Frenchad7a2922008-02-07 23:25:02 +0000489 result = -result;
Steve Frenchb815f1e52006-10-02 05:53:29 +0000490 server->timeAdj = result;
Steve French25ee4a92006-09-30 00:54:23 +0000491 } else {
Steve Frenchb815f1e52006-10-02 05:53:29 +0000492 server->timeAdj = (int)tmp;
493 server->timeAdj *= 60; /* also in seconds */
Steve French25ee4a92006-09-30 00:54:23 +0000494 }
Joe Perchesb6b38f72010-04-21 03:50:45 +0000495 cFYI(1, "server->timeAdj: %d seconds", server->timeAdj);
Steve French25ee4a92006-09-30 00:54:23 +0000496
Steve French39798772006-05-31 22:40:51 +0000497
Steve French254e55e2006-06-04 05:53:15 +0000498 /* BB get server time for time conversions and add
Steve French50c2f752007-07-13 00:33:32 +0000499 code to use it and timezone since this is not UTC */
Steve French39798772006-05-31 22:40:51 +0000500
Steve French50c2f752007-07-13 00:33:32 +0000501 if (rsp->EncryptionKeyLength ==
Steve French25ee4a92006-09-30 00:54:23 +0000502 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500503 memcpy(ses->server->cryptkey, rsp->EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000504 CIFS_CRYPTO_KEY_SIZE);
505 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
506 rc = -EIO; /* need cryptkey unless plain text */
507 goto neg_err_exit;
508 }
Steve French39798772006-05-31 22:40:51 +0000509
Steve Frenchf19159d2010-04-21 04:12:10 +0000510 cFYI(1, "LANMAN negotiated");
Steve French254e55e2006-06-04 05:53:15 +0000511 /* we will not end up setting signing flags - as no signing
512 was in LANMAN and server did not return the flags on */
513 goto signing_check;
Steve French7c7b25b2006-06-01 19:20:10 +0000514#else /* weak security disabled */
Steve French790fe572007-07-07 19:25:05 +0000515 } else if (pSMBr->hdr.WordCount == 13) {
Steve Frenchf19159d2010-04-21 04:12:10 +0000516 cERROR(1, "mount failed, cifs module not built "
517 "with CIFS_WEAK_PW_HASH support");
Dan Carpenter8212cf72010-03-15 11:22:26 +0300518 rc = -EOPNOTSUPP;
Steve French7c7b25b2006-06-01 19:20:10 +0000519#endif /* WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000520 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000521 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000522 /* unknown wct */
523 rc = -EOPNOTSUPP;
524 goto neg_err_exit;
525 }
526 /* else wct == 17 NTLM */
527 server->secMode = pSMBr->SecurityMode;
Steve French790fe572007-07-07 19:25:05 +0000528 if ((server->secMode & SECMODE_USER) == 0)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000529 cFYI(1, "share mode security");
Steve French39798772006-05-31 22:40:51 +0000530
Steve French790fe572007-07-07 19:25:05 +0000531 if ((server->secMode & SECMODE_PW_ENCRYPT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000532#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French750d1152006-06-27 06:28:30 +0000533 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000534#endif /* CIFS_WEAK_PW_HASH */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000535 cERROR(1, "Server requests plain text password"
536 " but client support disabled");
Steve French9312f672006-06-04 22:21:07 +0000537
Steve French790fe572007-07-07 19:25:05 +0000538 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
Steve French254e55e2006-06-04 05:53:15 +0000539 server->secType = NTLMv2;
Steve French790fe572007-07-07 19:25:05 +0000540 else if (secFlags & CIFSSEC_MAY_NTLM)
Steve French254e55e2006-06-04 05:53:15 +0000541 server->secType = NTLM;
Steve French790fe572007-07-07 19:25:05 +0000542 else if (secFlags & CIFSSEC_MAY_NTLMV2)
Steve Frenchf40c5622006-06-28 00:13:38 +0000543 server->secType = NTLMv2;
Steve Frencha0136892007-10-04 20:05:09 +0000544 else if (secFlags & CIFSSEC_MAY_KRB5)
545 server->secType = Kerberos;
Steve Frenchac683922009-05-06 04:16:04 +0000546 else if (secFlags & CIFSSEC_MAY_NTLMSSP)
Steve Frenchf46c7232009-06-25 03:04:20 +0000547 server->secType = RawNTLMSSP;
Steve Frencha0136892007-10-04 20:05:09 +0000548 else if (secFlags & CIFSSEC_MAY_LANMAN)
549 server->secType = LANMAN;
550/* #ifdef CONFIG_CIFS_EXPERIMENTAL
551 else if (secFlags & CIFSSEC_MAY_PLNTXT)
552 server->secType = ??
553#endif */
554 else {
555 rc = -EOPNOTSUPP;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000556 cERROR(1, "Invalid security type");
Steve Frencha0136892007-10-04 20:05:09 +0000557 goto neg_err_exit;
558 }
559 /* else ... any others ...? */
Steve French7c7b25b2006-06-01 19:20:10 +0000560
Steve French254e55e2006-06-04 05:53:15 +0000561 /* one byte, so no need to convert this or EncryptionKeyLen from
562 little endian */
563 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
564 /* probably no need to store and check maxvcs */
565 server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve Frencheca6acf2009-02-20 05:43:09 +0000567 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000568 cFYI(DBG2, "Max buf = %d", ses->server->maxBuf);
Steve French254e55e2006-06-04 05:53:15 +0000569 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
570 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e52006-10-02 05:53:29 +0000571 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
572 server->timeAdj *= 60;
Steve French254e55e2006-06-04 05:53:15 +0000573 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500574 memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000575 CIFS_CRYPTO_KEY_SIZE);
576 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
577 && (pSMBr->EncryptionKeyLength == 0)) {
578 /* decode security blob */
579 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
580 rc = -EIO; /* no crypt key only if plain text pwd */
581 goto neg_err_exit;
582 }
583
584 /* BB might be helpful to save off the domain of server here */
585
Steve French50c2f752007-07-13 00:33:32 +0000586 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
Steve French254e55e2006-06-04 05:53:15 +0000587 (server->capabilities & CAP_EXTENDED_SECURITY)) {
588 count = pSMBr->ByteCount;
Jeff Laytone187e442007-10-16 17:10:44 +0000589 if (count < 16) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 rc = -EIO;
Jeff Laytone187e442007-10-16 17:10:44 +0000591 goto neg_err_exit;
592 }
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530593 spin_lock(&cifs_tcp_ses_lock);
Jeff Laytone7ddee92008-11-14 13:44:38 -0500594 if (server->srv_count > 1) {
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530595 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000596 if (memcmp(server->server_GUID,
597 pSMBr->u.extended_response.
598 GUID, 16) != 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000599 cFYI(1, "server UID changed");
Steve French254e55e2006-06-04 05:53:15 +0000600 memcpy(server->server_GUID,
Jeff Laytone187e442007-10-16 17:10:44 +0000601 pSMBr->u.extended_response.GUID,
602 16);
603 }
Jeff Laytone7ddee92008-11-14 13:44:38 -0500604 } else {
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530605 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000606 memcpy(server->server_GUID,
607 pSMBr->u.extended_response.GUID, 16);
Jeff Laytone7ddee92008-11-14 13:44:38 -0500608 }
Jeff Laytone187e442007-10-16 17:10:44 +0000609
610 if (count == 16) {
611 server->secType = RawNTLMSSP;
Steve French254e55e2006-06-04 05:53:15 +0000612 } else {
613 rc = decode_negTokenInit(pSMBr->u.extended_response.
Jeff Layton26efa0b2010-04-24 07:57:49 -0400614 SecurityBlob, count - 16,
615 server);
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000616 if (rc == 1)
Jeff Laytone5459372007-11-03 05:11:06 +0000617 rc = 0;
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000618 else
Steve French254e55e2006-06-04 05:53:15 +0000619 rc = -EINVAL;
Shirish Pargaonkar2b149f12010-09-18 22:02:18 -0500620 if (server->secType == Kerberos) {
621 if (!server->sec_kerberos &&
622 !server->sec_mskerberos)
623 rc = -EOPNOTSUPP;
624 } else if (server->secType == RawNTLMSSP) {
625 if (!server->sec_ntlmssp)
626 rc = -EOPNOTSUPP;
627 } else
628 rc = -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 }
Steve French254e55e2006-06-04 05:53:15 +0000630 } else
631 server->capabilities &= ~CAP_EXTENDED_SECURITY;
632
Steve French6344a422006-06-12 04:18:35 +0000633#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French254e55e2006-06-04 05:53:15 +0000634signing_check:
Steve French6344a422006-06-12 04:18:35 +0000635#endif
Steve French762e5ab2007-06-28 18:41:42 +0000636 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
637 /* MUST_SIGN already includes the MAY_SIGN FLAG
638 so if this is zero it means that signing is disabled */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000639 cFYI(1, "Signing disabled");
Steve Frenchabb63d62007-10-18 02:58:40 +0000640 if (server->secMode & SECMODE_SIGN_REQUIRED) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000641 cERROR(1, "Server requires "
Jeff Layton7111d212007-10-16 16:50:25 +0000642 "packet signing to be enabled in "
Joe Perchesb6b38f72010-04-21 03:50:45 +0000643 "/proc/fs/cifs/SecurityFlags.");
Steve Frenchabb63d62007-10-18 02:58:40 +0000644 rc = -EOPNOTSUPP;
645 }
Steve French50c2f752007-07-13 00:33:32 +0000646 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000647 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Steve French762e5ab2007-06-28 18:41:42 +0000648 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
649 /* signing required */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000650 cFYI(1, "Must sign - secFlags 0x%x", secFlags);
Steve French762e5ab2007-06-28 18:41:42 +0000651 if ((server->secMode &
652 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000653 cERROR(1, "signing required but server lacks support");
Jeff38c10a12007-07-06 21:10:07 +0000654 rc = -EOPNOTSUPP;
Steve French762e5ab2007-06-28 18:41:42 +0000655 } else
656 server->secMode |= SECMODE_SIGN_REQUIRED;
657 } else {
658 /* signing optional ie CIFSSEC_MAY_SIGN */
Steve French790fe572007-07-07 19:25:05 +0000659 if ((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
Steve French50c2f752007-07-13 00:33:32 +0000660 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000661 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 }
Steve French50c2f752007-07-13 00:33:32 +0000663
664neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700665 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000666
Joe Perchesb6b38f72010-04-21 03:50:45 +0000667 cFYI(1, "negprot rc %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 return rc;
669}
670
671int
672CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
673{
674 struct smb_hdr *smb_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676
Joe Perchesb6b38f72010-04-21 03:50:45 +0000677 cFYI(1, "In tree disconnect");
Jeff Laytonf1987b42008-11-15 11:12:47 -0500678
679 /* BB: do we need to check this? These should never be NULL. */
680 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
681 return -EIO;
682
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 /*
Jeff Laytonf1987b42008-11-15 11:12:47 -0500684 * No need to return error on this operation if tid invalidated and
685 * closed on server already e.g. due to tcp session crashing. Also,
686 * the tcon is no longer on the list, so no need to take lock before
687 * checking this.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 */
Steve French268875b2009-06-25 00:29:21 +0000689 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
Steve French50c2f752007-07-13 00:33:32 +0000690 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691
Steve French50c2f752007-07-13 00:33:32 +0000692 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700693 (void **)&smb_buffer);
Jeff Laytonf1987b42008-11-15 11:12:47 -0500694 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 return rc;
Steve French133672e2007-11-13 22:41:37 +0000696
697 rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000699 cFYI(1, "Tree disconnect failed %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700
Steve French50c2f752007-07-13 00:33:32 +0000701 /* No need to return error on this operation if tid invalidated and
Jeff Laytonf1987b42008-11-15 11:12:47 -0500702 closed on server already e.g. due to tcp session crashing */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 if (rc == -EAGAIN)
704 rc = 0;
705
706 return rc;
707}
708
Jeff Layton766fdbb2011-01-11 07:24:21 -0500709/*
710 * This is a no-op for now. We're not really interested in the reply, but
711 * rather in the fact that the server sent one and that server->lstrp
712 * gets updated.
713 *
714 * FIXME: maybe we should consider checking that the reply matches request?
715 */
716static void
717cifs_echo_callback(struct mid_q_entry *mid)
718{
719 struct TCP_Server_Info *server = mid->callback_data;
720
721 DeleteMidQEntry(mid);
722 atomic_dec(&server->inFlight);
723 wake_up(&server->request_q);
724}
725
726int
727CIFSSMBEcho(struct TCP_Server_Info *server)
728{
729 ECHO_REQ *smb;
730 int rc = 0;
731
732 cFYI(1, "In echo request");
733
734 rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
735 if (rc)
736 return rc;
737
738 /* set up echo request */
739 smb->hdr.Tid = cpu_to_le16(0xffff);
740 smb->hdr.WordCount = cpu_to_le16(1);
741 smb->EchoCount = cpu_to_le16(1);
742 smb->ByteCount = cpu_to_le16(1);
743 smb->Data[0] = 'a';
744 smb->hdr.smb_buf_length += 3;
745
746 rc = cifs_call_async(server, (struct smb_hdr *)smb,
747 cifs_echo_callback, server);
748 if (rc)
749 cFYI(1, "Echo request failed: %d", rc);
750
751 cifs_small_buf_release(smb);
752
753 return rc;
754}
755
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756int
757CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
758{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 LOGOFF_ANDX_REQ *pSMB;
760 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761
Joe Perchesb6b38f72010-04-21 03:50:45 +0000762 cFYI(1, "In SMBLogoff for session disconnect");
Jeff Layton14fbf502008-11-14 13:53:46 -0500763
764 /*
765 * BB: do we need to check validity of ses and server? They should
766 * always be valid since we have an active reference. If not, that
767 * should probably be a BUG()
768 */
769 if (!ses || !ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 return -EIO;
771
Steve Frenchd7b619c2010-02-25 05:36:46 +0000772 mutex_lock(&ses->session_mutex);
Steve French3b795212008-11-13 19:45:32 +0000773 if (ses->need_reconnect)
774 goto session_already_dead; /* no need to send SMBlogoff if uid
775 already closed due to reconnect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
777 if (rc) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000778 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 return rc;
780 }
781
Steve French3b795212008-11-13 19:45:32 +0000782 pSMB->hdr.Mid = GetNextMid(ses->server);
Steve French1982c342005-08-17 12:38:22 -0700783
Steve French3b795212008-11-13 19:45:32 +0000784 if (ses->server->secMode &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
786 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787
788 pSMB->hdr.Uid = ses->Suid;
789
790 pSMB->AndXCommand = 0xFF;
Steve French133672e2007-11-13 22:41:37 +0000791 rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
Steve French3b795212008-11-13 19:45:32 +0000792session_already_dead:
Steve Frenchd7b619c2010-02-25 05:36:46 +0000793 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794
795 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000796 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797 error */
798 if (rc == -EAGAIN)
799 rc = 0;
800 return rc;
801}
802
803int
Steve French2d785a52007-07-15 01:48:57 +0000804CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
805 __u16 type, const struct nls_table *nls_codepage, int remap)
806{
807 TRANSACTION2_SPI_REQ *pSMB = NULL;
808 TRANSACTION2_SPI_RSP *pSMBr = NULL;
809 struct unlink_psx_rq *pRqD;
810 int name_len;
811 int rc = 0;
812 int bytes_returned = 0;
813 __u16 params, param_offset, offset, byte_count;
814
Joe Perchesb6b38f72010-04-21 03:50:45 +0000815 cFYI(1, "In POSIX delete");
Steve French2d785a52007-07-15 01:48:57 +0000816PsxDelete:
817 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
818 (void **) &pSMBr);
819 if (rc)
820 return rc;
821
822 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
823 name_len =
824 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
825 PATH_MAX, nls_codepage, remap);
826 name_len++; /* trailing null */
827 name_len *= 2;
828 } else { /* BB add path length overrun check */
829 name_len = strnlen(fileName, PATH_MAX);
830 name_len++; /* trailing null */
831 strncpy(pSMB->FileName, fileName, name_len);
832 }
833
834 params = 6 + name_len;
835 pSMB->MaxParameterCount = cpu_to_le16(2);
836 pSMB->MaxDataCount = 0; /* BB double check this with jra */
837 pSMB->MaxSetupCount = 0;
838 pSMB->Reserved = 0;
839 pSMB->Flags = 0;
840 pSMB->Timeout = 0;
841 pSMB->Reserved2 = 0;
842 param_offset = offsetof(struct smb_com_transaction2_spi_req,
843 InformationLevel) - 4;
844 offset = param_offset + params;
845
846 /* Setup pointer to Request Data (inode type) */
847 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
848 pRqD->type = cpu_to_le16(type);
849 pSMB->ParameterOffset = cpu_to_le16(param_offset);
850 pSMB->DataOffset = cpu_to_le16(offset);
851 pSMB->SetupCount = 1;
852 pSMB->Reserved3 = 0;
853 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
854 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
855
856 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
857 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
858 pSMB->ParameterCount = cpu_to_le16(params);
859 pSMB->TotalParameterCount = pSMB->ParameterCount;
860 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
861 pSMB->Reserved4 = 0;
862 pSMB->hdr.smb_buf_length += byte_count;
863 pSMB->ByteCount = cpu_to_le16(byte_count);
864 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
865 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000866 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000867 cFYI(1, "Posix delete returned %d", rc);
Steve French2d785a52007-07-15 01:48:57 +0000868 cifs_buf_release(pSMB);
869
870 cifs_stats_inc(&tcon->num_deletes);
871
872 if (rc == -EAGAIN)
873 goto PsxDelete;
874
875 return rc;
876}
877
878int
Steve French737b7582005-04-28 22:41:06 -0700879CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
880 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881{
882 DELETE_FILE_REQ *pSMB = NULL;
883 DELETE_FILE_RSP *pSMBr = NULL;
884 int rc = 0;
885 int bytes_returned;
886 int name_len;
887
888DelFileRetry:
889 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
890 (void **) &pSMBr);
891 if (rc)
892 return rc;
893
894 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
895 name_len =
Steve French50c2f752007-07-13 00:33:32 +0000896 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
Steve French737b7582005-04-28 22:41:06 -0700897 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 name_len++; /* trailing null */
899 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700900 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 name_len = strnlen(fileName, PATH_MAX);
902 name_len++; /* trailing null */
903 strncpy(pSMB->fileName, fileName, name_len);
904 }
905 pSMB->SearchAttributes =
906 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
907 pSMB->BufferFormat = 0x04;
908 pSMB->hdr.smb_buf_length += name_len + 1;
909 pSMB->ByteCount = cpu_to_le16(name_len + 1);
910 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
911 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700912 cifs_stats_inc(&tcon->num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000913 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000914 cFYI(1, "Error in RMFile = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915
916 cifs_buf_release(pSMB);
917 if (rc == -EAGAIN)
918 goto DelFileRetry;
919
920 return rc;
921}
922
923int
Steve French50c2f752007-07-13 00:33:32 +0000924CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
Steve French737b7582005-04-28 22:41:06 -0700925 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926{
927 DELETE_DIRECTORY_REQ *pSMB = NULL;
928 DELETE_DIRECTORY_RSP *pSMBr = NULL;
929 int rc = 0;
930 int bytes_returned;
931 int name_len;
932
Joe Perchesb6b38f72010-04-21 03:50:45 +0000933 cFYI(1, "In CIFSSMBRmDir");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934RmDirRetry:
935 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
936 (void **) &pSMBr);
937 if (rc)
938 return rc;
939
940 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French737b7582005-04-28 22:41:06 -0700941 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
942 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943 name_len++; /* trailing null */
944 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700945 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946 name_len = strnlen(dirName, PATH_MAX);
947 name_len++; /* trailing null */
948 strncpy(pSMB->DirName, dirName, name_len);
949 }
950
951 pSMB->BufferFormat = 0x04;
952 pSMB->hdr.smb_buf_length += name_len + 1;
953 pSMB->ByteCount = cpu_to_le16(name_len + 1);
954 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
955 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700956 cifs_stats_inc(&tcon->num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000957 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000958 cFYI(1, "Error in RMDir = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959
960 cifs_buf_release(pSMB);
961 if (rc == -EAGAIN)
962 goto RmDirRetry;
963 return rc;
964}
965
966int
967CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -0700968 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969{
970 int rc = 0;
971 CREATE_DIRECTORY_REQ *pSMB = NULL;
972 CREATE_DIRECTORY_RSP *pSMBr = NULL;
973 int bytes_returned;
974 int name_len;
975
Joe Perchesb6b38f72010-04-21 03:50:45 +0000976 cFYI(1, "In CIFSSMBMkDir");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977MkDirRetry:
978 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
979 (void **) &pSMBr);
980 if (rc)
981 return rc;
982
983 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +0000984 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
Steve French737b7582005-04-28 22:41:06 -0700985 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 name_len++; /* trailing null */
987 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700988 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989 name_len = strnlen(name, PATH_MAX);
990 name_len++; /* trailing null */
991 strncpy(pSMB->DirName, name, name_len);
992 }
993
994 pSMB->BufferFormat = 0x04;
995 pSMB->hdr.smb_buf_length += name_len + 1;
996 pSMB->ByteCount = cpu_to_le16(name_len + 1);
997 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
998 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700999 cifs_stats_inc(&tcon->num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +00001000 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001001 cFYI(1, "Error in Mkdir = %d", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07001002
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 cifs_buf_release(pSMB);
1004 if (rc == -EAGAIN)
1005 goto MkDirRetry;
1006 return rc;
1007}
1008
Steve French2dd29d32007-04-23 22:07:35 +00001009int
1010CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
Steve Frenchad7a2922008-02-07 23:25:02 +00001011 __u64 mode, __u16 *netfid, FILE_UNIX_BASIC_INFO *pRetData,
Steve French50c2f752007-07-13 00:33:32 +00001012 __u32 *pOplock, const char *name,
Steve French2dd29d32007-04-23 22:07:35 +00001013 const struct nls_table *nls_codepage, int remap)
1014{
1015 TRANSACTION2_SPI_REQ *pSMB = NULL;
1016 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1017 int name_len;
1018 int rc = 0;
1019 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001020 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +00001021 OPEN_PSX_REQ *pdata;
1022 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +00001023
Joe Perchesb6b38f72010-04-21 03:50:45 +00001024 cFYI(1, "In POSIX Create");
Steve French2dd29d32007-04-23 22:07:35 +00001025PsxCreat:
1026 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1027 (void **) &pSMBr);
1028 if (rc)
1029 return rc;
1030
1031 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1032 name_len =
1033 cifsConvertToUCS((__le16 *) pSMB->FileName, name,
1034 PATH_MAX, nls_codepage, remap);
1035 name_len++; /* trailing null */
1036 name_len *= 2;
1037 } else { /* BB improve the check for buffer overruns BB */
1038 name_len = strnlen(name, PATH_MAX);
1039 name_len++; /* trailing null */
1040 strncpy(pSMB->FileName, name, name_len);
1041 }
1042
1043 params = 6 + name_len;
1044 count = sizeof(OPEN_PSX_REQ);
1045 pSMB->MaxParameterCount = cpu_to_le16(2);
1046 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1047 pSMB->MaxSetupCount = 0;
1048 pSMB->Reserved = 0;
1049 pSMB->Flags = 0;
1050 pSMB->Timeout = 0;
1051 pSMB->Reserved2 = 0;
1052 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001053 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001054 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001055 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001056 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001057 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001058 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001059 pdata->OpenFlags = cpu_to_le32(*pOplock);
1060 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1061 pSMB->DataOffset = cpu_to_le16(offset);
1062 pSMB->SetupCount = 1;
1063 pSMB->Reserved3 = 0;
1064 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1065 byte_count = 3 /* pad */ + params + count;
1066
1067 pSMB->DataCount = cpu_to_le16(count);
1068 pSMB->ParameterCount = cpu_to_le16(params);
1069 pSMB->TotalDataCount = pSMB->DataCount;
1070 pSMB->TotalParameterCount = pSMB->ParameterCount;
1071 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1072 pSMB->Reserved4 = 0;
Steve French50c2f752007-07-13 00:33:32 +00001073 pSMB->hdr.smb_buf_length += byte_count;
Steve French2dd29d32007-04-23 22:07:35 +00001074 pSMB->ByteCount = cpu_to_le16(byte_count);
1075 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1076 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1077 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001078 cFYI(1, "Posix create returned %d", rc);
Steve French2dd29d32007-04-23 22:07:35 +00001079 goto psx_create_err;
1080 }
1081
Joe Perchesb6b38f72010-04-21 03:50:45 +00001082 cFYI(1, "copying inode info");
Steve French2dd29d32007-04-23 22:07:35 +00001083 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1084
1085 if (rc || (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP))) {
1086 rc = -EIO; /* bad smb */
1087 goto psx_create_err;
1088 }
1089
1090 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001091 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001092 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001093
Steve French2dd29d32007-04-23 22:07:35 +00001094 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001095 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001096 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1097 /* Let caller know file was created so we can set the mode. */
1098 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001099 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001100 *pOplock |= CIFS_CREATE_ACTION;
1101 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001102 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1103 pRetData->Type = cpu_to_le32(-1); /* unknown */
Joe Perchesb6b38f72010-04-21 03:50:45 +00001104 cFYI(DBG2, "unknown type");
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001105 } else {
Steve French790fe572007-07-07 19:25:05 +00001106 if (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001107 + sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001108 cERROR(1, "Open response data too small");
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001109 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001110 goto psx_create_err;
1111 }
Steve French50c2f752007-07-13 00:33:32 +00001112 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001113 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001114 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001115 }
Steve French2dd29d32007-04-23 22:07:35 +00001116
1117psx_create_err:
1118 cifs_buf_release(pSMB);
1119
Steve French65bc98b2009-07-10 15:27:25 +00001120 if (posix_flags & SMB_O_DIRECTORY)
1121 cifs_stats_inc(&tcon->num_posixmkdirs);
1122 else
1123 cifs_stats_inc(&tcon->num_posixopens);
Steve French2dd29d32007-04-23 22:07:35 +00001124
1125 if (rc == -EAGAIN)
1126 goto PsxCreat;
1127
Steve French50c2f752007-07-13 00:33:32 +00001128 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001129}
1130
Steve Frencha9d02ad2005-08-24 23:06:05 -07001131static __u16 convert_disposition(int disposition)
1132{
1133 __u16 ofun = 0;
1134
1135 switch (disposition) {
1136 case FILE_SUPERSEDE:
1137 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1138 break;
1139 case FILE_OPEN:
1140 ofun = SMBOPEN_OAPPEND;
1141 break;
1142 case FILE_CREATE:
1143 ofun = SMBOPEN_OCREATE;
1144 break;
1145 case FILE_OPEN_IF:
1146 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1147 break;
1148 case FILE_OVERWRITE:
1149 ofun = SMBOPEN_OTRUNC;
1150 break;
1151 case FILE_OVERWRITE_IF:
1152 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1153 break;
1154 default:
Joe Perchesb6b38f72010-04-21 03:50:45 +00001155 cFYI(1, "unknown disposition %d", disposition);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001156 ofun = SMBOPEN_OAPPEND; /* regular open */
1157 }
1158 return ofun;
1159}
1160
Jeff Layton35fc37d2008-05-14 10:22:03 -07001161static int
1162access_flags_to_smbopen_mode(const int access_flags)
1163{
1164 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1165
1166 if (masked_flags == GENERIC_READ)
1167 return SMBOPEN_READ;
1168 else if (masked_flags == GENERIC_WRITE)
1169 return SMBOPEN_WRITE;
1170
1171 /* just go for read/write */
1172 return SMBOPEN_READWRITE;
1173}
1174
Steve Frencha9d02ad2005-08-24 23:06:05 -07001175int
1176SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
1177 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001178 const int access_flags, const int create_options, __u16 *netfid,
1179 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001180 const struct nls_table *nls_codepage, int remap)
1181{
1182 int rc = -EACCES;
1183 OPENX_REQ *pSMB = NULL;
1184 OPENX_RSP *pSMBr = NULL;
1185 int bytes_returned;
1186 int name_len;
1187 __u16 count;
1188
1189OldOpenRetry:
1190 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1191 (void **) &pSMBr);
1192 if (rc)
1193 return rc;
1194
1195 pSMB->AndXCommand = 0xFF; /* none */
1196
1197 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1198 count = 1; /* account for one byte pad to word boundary */
1199 name_len =
1200 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1201 fileName, PATH_MAX, nls_codepage, remap);
1202 name_len++; /* trailing null */
1203 name_len *= 2;
1204 } else { /* BB improve check for buffer overruns BB */
1205 count = 0; /* no pad */
1206 name_len = strnlen(fileName, PATH_MAX);
1207 name_len++; /* trailing null */
1208 strncpy(pSMB->fileName, fileName, name_len);
1209 }
1210 if (*pOplock & REQ_OPLOCK)
1211 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001212 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001213 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001214
Steve Frencha9d02ad2005-08-24 23:06:05 -07001215 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001216 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001217 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1218 /* set file as system file if special file such
1219 as fifo and server expecting SFU style and
1220 no Unix extensions */
1221
Steve French790fe572007-07-07 19:25:05 +00001222 if (create_options & CREATE_OPTION_SPECIAL)
1223 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001224 else /* BB FIXME BB */
1225 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001226
Jeff Layton67750fb2008-05-09 22:28:02 +00001227 if (create_options & CREATE_OPTION_READONLY)
1228 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001229
1230 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001231/* pSMB->CreateOptions = cpu_to_le32(create_options &
1232 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001233 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001234
1235 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001236 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001237 count += name_len;
1238 pSMB->hdr.smb_buf_length += count;
1239
1240 pSMB->ByteCount = cpu_to_le16(count);
1241 /* long_op set to 1 to allow for oplock break timeouts */
1242 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00001243 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001244 cifs_stats_inc(&tcon->num_opens);
1245 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001246 cFYI(1, "Error in Open = %d", rc);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001247 } else {
1248 /* BB verify if wct == 15 */
1249
Steve French582d21e2008-05-13 04:54:12 +00001250/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001251
1252 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1253 /* Let caller know file was created so we can set the mode. */
1254 /* Do we care about the CreateAction in any other cases? */
1255 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001256/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001257 *pOplock |= CIFS_CREATE_ACTION; */
1258 /* BB FIXME END */
1259
Steve French790fe572007-07-07 19:25:05 +00001260 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001261 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1262 pfile_info->LastAccessTime = 0; /* BB fixme */
1263 pfile_info->LastWriteTime = 0; /* BB fixme */
1264 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001265 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001266 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001267 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001268 pfile_info->AllocationSize =
1269 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1270 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001271 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001272 pfile_info->DeletePending = 0;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001273 }
1274 }
1275
1276 cifs_buf_release(pSMB);
1277 if (rc == -EAGAIN)
1278 goto OldOpenRetry;
1279 return rc;
1280}
1281
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282int
1283CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1284 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001285 const int access_flags, const int create_options, __u16 *netfid,
1286 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001287 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288{
1289 int rc = -EACCES;
1290 OPEN_REQ *pSMB = NULL;
1291 OPEN_RSP *pSMBr = NULL;
1292 int bytes_returned;
1293 int name_len;
1294 __u16 count;
1295
1296openRetry:
1297 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1298 (void **) &pSMBr);
1299 if (rc)
1300 return rc;
1301
1302 pSMB->AndXCommand = 0xFF; /* none */
1303
1304 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1305 count = 1; /* account for one byte pad to word boundary */
1306 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001307 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -07001308 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001309 name_len++; /* trailing null */
1310 name_len *= 2;
1311 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001312 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313 count = 0; /* no pad */
1314 name_len = strnlen(fileName, PATH_MAX);
1315 name_len++; /* trailing null */
1316 pSMB->NameLength = cpu_to_le16(name_len);
1317 strncpy(pSMB->fileName, fileName, name_len);
1318 }
1319 if (*pOplock & REQ_OPLOCK)
1320 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001321 else if (*pOplock & REQ_BATCHOPLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1324 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -07001325 /* set file as system file if special file such
1326 as fifo and server expecting SFU style and
1327 no Unix extensions */
Steve French790fe572007-07-07 19:25:05 +00001328 if (create_options & CREATE_OPTION_SPECIAL)
Steve Frencheda3c0292005-07-21 15:20:28 -07001329 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1330 else
1331 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Jeff Layton67750fb2008-05-09 22:28:02 +00001332
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333 /* XP does not handle ATTR_POSIX_SEMANTICS */
1334 /* but it helps speed up case sensitive checks for other
1335 servers such as Samba */
1336 if (tcon->ses->capabilities & CAP_UNIX)
1337 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1338
Jeff Layton67750fb2008-05-09 22:28:02 +00001339 if (create_options & CREATE_OPTION_READONLY)
1340 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1341
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1343 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -07001344 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001345 /* BB Expirement with various impersonation levels and verify */
1346 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347 pSMB->SecurityFlags =
1348 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1349
1350 count += name_len;
1351 pSMB->hdr.smb_buf_length += count;
1352
1353 pSMB->ByteCount = cpu_to_le16(count);
1354 /* long_op set to 1 to allow for oplock break timeouts */
1355 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00001356 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
Steve Frencha4544342005-08-24 13:59:35 -07001357 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001359 cFYI(1, "Error in Open = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360 } else {
Steve French09d1db52005-04-28 22:41:08 -07001361 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1363 /* Let caller know file was created so we can set the mode. */
1364 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001365 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve French50c2f752007-07-13 00:33:32 +00001366 *pOplock |= CIFS_CREATE_ACTION;
Steve French790fe572007-07-07 19:25:05 +00001367 if (pfile_info) {
Steve French61e74802008-12-03 00:57:54 +00001368 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1369 36 /* CreationTime to Attributes */);
1370 /* the file_info buf is endian converted by caller */
1371 pfile_info->AllocationSize = pSMBr->AllocationSize;
1372 pfile_info->EndOfFile = pSMBr->EndOfFile;
1373 pfile_info->NumberOfLinks = cpu_to_le32(1);
1374 pfile_info->DeletePending = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001377
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378 cifs_buf_release(pSMB);
1379 if (rc == -EAGAIN)
1380 goto openRetry;
1381 return rc;
1382}
1383
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384int
Steve French50c2f752007-07-13 00:33:32 +00001385CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
1386 const unsigned int count, const __u64 lseek, unsigned int *nbytes,
1387 char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001388{
1389 int rc = -EACCES;
1390 READ_REQ *pSMB = NULL;
1391 READ_RSP *pSMBr = NULL;
1392 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001393 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001394 int resp_buf_type = 0;
1395 struct kvec iov[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396
Joe Perchesb6b38f72010-04-21 03:50:45 +00001397 cFYI(1, "Reading %d bytes on fid %d", count, netfid);
Steve French790fe572007-07-07 19:25:05 +00001398 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001399 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001400 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001401 wct = 10; /* old style read */
Steve French4c3130e2008-12-09 00:28:16 +00001402 if ((lseek >> 32) > 0) {
1403 /* can not handle this big offset for old */
1404 return -EIO;
1405 }
1406 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407
1408 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001409 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410 if (rc)
1411 return rc;
1412
1413 /* tcon and ses pointer are checked in smb_init */
1414 if (tcon->ses->server == NULL)
1415 return -ECONNABORTED;
1416
Steve Frenchec637e32005-12-12 20:53:18 -08001417 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418 pSMB->Fid = netfid;
1419 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001420 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001421 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001422
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423 pSMB->Remaining = 0;
1424 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1425 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001426 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001427 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1428 else {
1429 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001430 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001431 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001432 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001433 }
Steve Frenchec637e32005-12-12 20:53:18 -08001434
1435 iov[0].iov_base = (char *)pSMB;
1436 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
Steve Frencha761ac52007-10-18 21:45:27 +00001437 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Steve French133672e2007-11-13 22:41:37 +00001438 &resp_buf_type, CIFS_STD_OP | CIFS_LOG_ERROR);
Steve Frencha4544342005-08-24 13:59:35 -07001439 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001440 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001441 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001442 cERROR(1, "Send error in read = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443 } else {
1444 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1445 data_length = data_length << 16;
1446 data_length += le16_to_cpu(pSMBr->DataLength);
1447 *nbytes = data_length;
1448
1449 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001450 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451 || (data_length > count)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001452 cFYI(1, "bad length %d for count %d",
1453 data_length, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454 rc = -EIO;
1455 *nbytes = 0;
1456 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001457 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001458 le16_to_cpu(pSMBr->DataOffset);
1459/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001460 cERROR(1, "Faulting on read rc = %d",rc);
Steve French50c2f752007-07-13 00:33:32 +00001461 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001462 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001463 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001464 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465 }
1466 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467
Steve French4b8f9302006-02-26 16:41:18 +00001468/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001469 if (*buf) {
1470 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001471 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001472 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001473 cifs_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001474 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001475 /* return buffer to caller to free */
1476 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001477 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001478 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001479 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001480 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001481 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001482
1483 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001484 since file handle passed in no longer valid */
1485 return rc;
1486}
1487
Steve Frenchec637e32005-12-12 20:53:18 -08001488
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489int
1490CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1491 const int netfid, const unsigned int count,
1492 const __u64 offset, unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001493 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494{
1495 int rc = -EACCES;
1496 WRITE_REQ *pSMB = NULL;
1497 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001498 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499 __u32 bytes_sent;
1500 __u16 byte_count;
1501
Steve Frencha24e2d72010-04-03 17:20:21 +00001502 *nbytes = 0;
1503
Joe Perchesb6b38f72010-04-21 03:50:45 +00001504 /* cFYI(1, "write at %lld %d bytes", offset, count);*/
Steve French790fe572007-07-07 19:25:05 +00001505 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001506 return -ECONNABORTED;
1507
Steve French790fe572007-07-07 19:25:05 +00001508 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001509 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001510 else {
Steve French1c955182005-08-30 20:58:07 -07001511 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001512 if ((offset >> 32) > 0) {
1513 /* can not handle big offset for old srv */
1514 return -EIO;
1515 }
1516 }
Steve French1c955182005-08-30 20:58:07 -07001517
1518 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519 (void **) &pSMBr);
1520 if (rc)
1521 return rc;
1522 /* tcon and ses pointer are checked in smb_init */
1523 if (tcon->ses->server == NULL)
1524 return -ECONNABORTED;
1525
1526 pSMB->AndXCommand = 0xFF; /* none */
1527 pSMB->Fid = netfid;
1528 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001529 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001530 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001531
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532 pSMB->Reserved = 0xFFFFFFFF;
1533 pSMB->WriteMode = 0;
1534 pSMB->Remaining = 0;
1535
Steve French50c2f752007-07-13 00:33:32 +00001536 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537 can send more if LARGE_WRITE_X capability returned by the server and if
1538 our buffer is big enough or if we convert to iovecs on socket writes
1539 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001540 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1542 } else {
1543 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1544 & ~0xFF;
1545 }
1546
1547 if (bytes_sent > count)
1548 bytes_sent = count;
1549 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001550 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001551 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001552 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001553 else if (ubuf) {
1554 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555 cifs_buf_release(pSMB);
1556 return -EFAULT;
1557 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001558 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559 /* No buffer */
1560 cifs_buf_release(pSMB);
1561 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001562 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001563 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001564 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001565 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001566 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001567
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1569 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenche30dcf32005-09-20 20:49:16 -07001570 pSMB->hdr.smb_buf_length += byte_count;
Steve French1c955182005-08-30 20:58:07 -07001571
Steve French790fe572007-07-07 19:25:05 +00001572 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001573 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001574 else { /* old style write has byte count 4 bytes earlier
1575 so 4 bytes pad */
1576 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001577 (struct smb_com_writex_req *)pSMB;
1578 pSMBW->ByteCount = cpu_to_le16(byte_count);
1579 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580
1581 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1582 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001583 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00001585 cFYI(1, "Send error in write = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586 } else {
1587 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1588 *nbytes = (*nbytes) << 16;
1589 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301590
1591 /*
1592 * Mask off high 16 bits when bytes written as returned by the
1593 * server is greater than bytes requested by the client. Some
1594 * OS/2 servers are known to set incorrect CountHigh values.
1595 */
1596 if (*nbytes > count)
1597 *nbytes &= 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598 }
1599
1600 cifs_buf_release(pSMB);
1601
Steve French50c2f752007-07-13 00:33:32 +00001602 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603 since file handle passed in no longer valid */
1604
1605 return rc;
1606}
1607
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001608int
1609CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610 const int netfid, const unsigned int count,
Steve French3e844692005-10-03 13:37:24 -07001611 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1612 int n_vec, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001613{
1614 int rc = -EACCES;
1615 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001616 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001617 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001618 int resp_buf_type = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001620 *nbytes = 0;
1621
Joe Perchesb6b38f72010-04-21 03:50:45 +00001622 cFYI(1, "write2 at %lld %d bytes", (long long)offset, count);
Steve Frenchff7feac2005-11-15 16:45:16 -08001623
Steve French4c3130e2008-12-09 00:28:16 +00001624 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07001625 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001626 } else {
Steve French8cc64c62005-10-03 13:49:43 -07001627 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001628 if ((offset >> 32) > 0) {
1629 /* can not handle big offset for old srv */
1630 return -EIO;
1631 }
1632 }
Steve French8cc64c62005-10-03 13:49:43 -07001633 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634 if (rc)
1635 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001636 /* tcon and ses pointer are checked in smb_init */
1637 if (tcon->ses->server == NULL)
1638 return -ECONNABORTED;
1639
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001640 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001641 pSMB->Fid = netfid;
1642 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001643 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001644 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645 pSMB->Reserved = 0xFFFFFFFF;
1646 pSMB->WriteMode = 0;
1647 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001648
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001650 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001651
Steve French3e844692005-10-03 13:37:24 -07001652 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1653 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001654 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
Steve French790fe572007-07-07 19:25:05 +00001655 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001656 pSMB->hdr.smb_buf_length += count+1;
1657 else /* wct == 12 */
Steve French790fe572007-07-07 19:25:05 +00001658 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1659 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 }
1758 pSMB->hdr.smb_buf_length += count;
1759 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;
1849 pSMB->hdr.smb_buf_length += byte_count;
1850 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;
1856 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1857 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
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001872 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1873 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
1894 pLockData->fl_start = parm_data->start;
1895 pLockData->fl_end = parm_data->start +
1896 parm_data->length - 1;
1897 pLockData->fl_pid = parm_data->pid;
1898 }
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;
2022 pSMB->hdr.smb_buf_length += count;
2023 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;
2102 pSMB->hdr.smb_buf_length += byte_count;
2103 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;
2169 pSMB->hdr.smb_buf_length += count;
2170 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;
2259 pSMB->hdr.smb_buf_length += byte_count;
2260 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;
2345 pSMB->hdr.smb_buf_length += byte_count;
2346 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;
2416 pSMB->hdr.smb_buf_length += count;
2417 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;
2487 pSMB->hdr.smb_buf_length += byte_count;
2488 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 Layton460b9692009-04-30 07:17:56 -04002499 if (rc || (pSMBr->ByteCount < 2))
2500 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
Parag Warudkarc9489772007-10-23 18:09:48 +00002526#ifdef CONFIG_CIFS_EXPERIMENTAL
Linus Torvalds1da177e2005-04-16 15:20:36 -07002527int
2528CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2529 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00002530 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002531 const struct nls_table *nls_codepage)
2532{
2533 int rc = 0;
2534 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00002535 struct smb_com_transaction_ioctl_req *pSMB;
2536 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002537
Joe Perchesb6b38f72010-04-21 03:50:45 +00002538 cFYI(1, "In Windows reparse style QueryLink for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002539 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2540 (void **) &pSMBr);
2541 if (rc)
2542 return rc;
2543
2544 pSMB->TotalParameterCount = 0 ;
2545 pSMB->TotalDataCount = 0;
2546 pSMB->MaxParameterCount = cpu_to_le32(2);
2547 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002548 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2549 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002550 pSMB->MaxSetupCount = 4;
2551 pSMB->Reserved = 0;
2552 pSMB->ParameterOffset = 0;
2553 pSMB->DataCount = 0;
2554 pSMB->DataOffset = 0;
2555 pSMB->SetupCount = 4;
2556 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2557 pSMB->ParameterCount = pSMB->TotalParameterCount;
2558 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2559 pSMB->IsFsctl = 1; /* FSCTL */
2560 pSMB->IsRootFlag = 0;
2561 pSMB->Fid = fid; /* file handle always le */
2562 pSMB->ByteCount = 0;
2563
2564 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2565 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2566 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002567 cFYI(1, "Send error in QueryReparseLinkInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002568 } else { /* decode response */
2569 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2570 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
Steve Frenchafe48c32009-05-02 05:25:46 +00002571 if ((pSMBr->ByteCount < 2) || (data_offset > 512)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002572 /* BB also check enough total bytes returned */
2573 rc = -EIO; /* bad smb */
Steve Frenchafe48c32009-05-02 05:25:46 +00002574 goto qreparse_out;
2575 }
2576 if (data_count && (data_count < 2048)) {
2577 char *end_of_smb = 2 /* sizeof byte count */ +
2578 pSMBr->ByteCount + (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002579
Steve Frenchafe48c32009-05-02 05:25:46 +00002580 struct reparse_data *reparse_buf =
Steve French50c2f752007-07-13 00:33:32 +00002581 (struct reparse_data *)
2582 ((char *)&pSMBr->hdr.Protocol
2583 + data_offset);
Steve Frenchafe48c32009-05-02 05:25:46 +00002584 if ((char *)reparse_buf >= end_of_smb) {
2585 rc = -EIO;
2586 goto qreparse_out;
2587 }
2588 if ((reparse_buf->LinkNamesBuf +
2589 reparse_buf->TargetNameOffset +
2590 reparse_buf->TargetNameLen) > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002591 cFYI(1, "reparse buf beyond SMB");
Steve Frenchafe48c32009-05-02 05:25:46 +00002592 rc = -EIO;
2593 goto qreparse_out;
2594 }
Steve French50c2f752007-07-13 00:33:32 +00002595
Steve Frenchafe48c32009-05-02 05:25:46 +00002596 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2597 cifs_from_ucs2(symlinkinfo, (__le16 *)
Steve French50c2f752007-07-13 00:33:32 +00002598 (reparse_buf->LinkNamesBuf +
2599 reparse_buf->TargetNameOffset),
Steve Frenchafe48c32009-05-02 05:25:46 +00002600 buflen,
2601 reparse_buf->TargetNameLen,
2602 nls_codepage, 0);
2603 } else { /* ASCII names */
2604 strncpy(symlinkinfo,
2605 reparse_buf->LinkNamesBuf +
2606 reparse_buf->TargetNameOffset,
2607 min_t(const int, buflen,
2608 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002609 }
Steve Frenchafe48c32009-05-02 05:25:46 +00002610 } else {
2611 rc = -EIO;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002612 cFYI(1, "Invalid return data count on "
2613 "get reparse info ioctl");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002614 }
Steve Frenchafe48c32009-05-02 05:25:46 +00002615 symlinkinfo[buflen] = 0; /* just in case so the caller
2616 does not go off the end of the buffer */
Joe Perchesb6b38f72010-04-21 03:50:45 +00002617 cFYI(1, "readlink result - %s", symlinkinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002618 }
Steve French989c7e52009-05-02 05:32:20 +00002619
Linus Torvalds1da177e2005-04-16 15:20:36 -07002620qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002621 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002622
2623 /* Note: On -EAGAIN error only caller can retry on handle based calls
2624 since file handle passed in no longer valid */
2625
2626 return rc;
2627}
Steve Frenchafe48c32009-05-02 05:25:46 +00002628#endif /* CIFS_EXPERIMENTAL */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002629
2630#ifdef CONFIG_CIFS_POSIX
2631
2632/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00002633static void cifs_convert_ace(posix_acl_xattr_entry *ace,
2634 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635{
2636 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002637 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2638 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2639 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesb6b38f72010-04-21 03:50:45 +00002640 /* cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002641
2642 return;
2643}
2644
2645/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00002646static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
2647 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002648{
2649 int size = 0;
2650 int i;
2651 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00002652 struct cifs_posix_ace *pACE;
2653 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
2654 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655
2656 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2657 return -EOPNOTSUPP;
2658
Steve French790fe572007-07-07 19:25:05 +00002659 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660 count = le16_to_cpu(cifs_acl->access_entry_count);
2661 pACE = &cifs_acl->ace_array[0];
2662 size = sizeof(struct cifs_posix_acl);
2663 size += sizeof(struct cifs_posix_ace) * count;
2664 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002665 if (size_of_data_area < size) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002666 cFYI(1, "bad CIFS POSIX ACL size %d vs. %d",
2667 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002668 return -EINVAL;
2669 }
Steve French790fe572007-07-07 19:25:05 +00002670 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002671 count = le16_to_cpu(cifs_acl->access_entry_count);
2672 size = sizeof(struct cifs_posix_acl);
2673 size += sizeof(struct cifs_posix_ace) * count;
2674/* skip past access ACEs to get to default ACEs */
2675 pACE = &cifs_acl->ace_array[count];
2676 count = le16_to_cpu(cifs_acl->default_entry_count);
2677 size += sizeof(struct cifs_posix_ace) * count;
2678 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002679 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002680 return -EINVAL;
2681 } else {
2682 /* illegal type */
2683 return -EINVAL;
2684 }
2685
2686 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00002687 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00002688 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00002689 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002690 return -ERANGE;
2691 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002692 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00002693 for (i = 0; i < count ; i++) {
2694 cifs_convert_ace(&local_acl->a_entries[i], pACE);
2695 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002696 }
2697 }
2698 return size;
2699}
2700
Steve French50c2f752007-07-13 00:33:32 +00002701static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
2702 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002703{
2704 __u16 rc = 0; /* 0 = ACL converted ok */
2705
Steve Frenchff7feac2005-11-15 16:45:16 -08002706 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2707 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002708 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00002709 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002710 /* Probably no need to le convert -1 on any arch but can not hurt */
2711 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00002712 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002713 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesb6b38f72010-04-21 03:50:45 +00002714 /*cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id);*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002715 return rc;
2716}
2717
2718/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00002719static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
2720 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002721{
2722 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00002723 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
2724 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002725 int count;
2726 int i;
2727
Steve French790fe572007-07-07 19:25:05 +00002728 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002729 return 0;
2730
2731 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesb6b38f72010-04-21 03:50:45 +00002732 cFYI(1, "setting acl with %d entries from buf of length %d and "
Steve French63135e02007-07-17 17:34:02 +00002733 "version of %d",
Joe Perchesb6b38f72010-04-21 03:50:45 +00002734 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00002735 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002736 cFYI(1, "unknown POSIX ACL version %d",
2737 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002738 return 0;
2739 }
2740 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00002741 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08002742 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00002743 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08002744 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002745 else {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002746 cFYI(1, "unknown ACL type %d", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002747 return 0;
2748 }
Steve French50c2f752007-07-13 00:33:32 +00002749 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002750 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2751 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00002752 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002753 /* ACE not converted */
2754 break;
2755 }
2756 }
Steve French790fe572007-07-07 19:25:05 +00002757 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002758 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2759 rc += sizeof(struct cifs_posix_acl);
2760 /* BB add check to make sure ACL does not overflow SMB */
2761 }
2762 return rc;
2763}
2764
2765int
2766CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002767 const unsigned char *searchName,
2768 char *acl_inf, const int buflen, const int acl_type,
2769 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002770{
2771/* SMB_QUERY_POSIX_ACL */
2772 TRANSACTION2_QPI_REQ *pSMB = NULL;
2773 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2774 int rc = 0;
2775 int bytes_returned;
2776 int name_len;
2777 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00002778
Joe Perchesb6b38f72010-04-21 03:50:45 +00002779 cFYI(1, "In GetPosixACL (Unix) for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002780
2781queryAclRetry:
2782 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2783 (void **) &pSMBr);
2784 if (rc)
2785 return rc;
Steve French50c2f752007-07-13 00:33:32 +00002786
Linus Torvalds1da177e2005-04-16 15:20:36 -07002787 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2788 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002789 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002790 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002791 name_len++; /* trailing null */
2792 name_len *= 2;
2793 pSMB->FileName[name_len] = 0;
2794 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00002795 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796 name_len = strnlen(searchName, PATH_MAX);
2797 name_len++; /* trailing null */
2798 strncpy(pSMB->FileName, searchName, name_len);
2799 }
2800
2801 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2802 pSMB->TotalDataCount = 0;
2803 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00002804 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002805 pSMB->MaxDataCount = cpu_to_le16(4000);
2806 pSMB->MaxSetupCount = 0;
2807 pSMB->Reserved = 0;
2808 pSMB->Flags = 0;
2809 pSMB->Timeout = 0;
2810 pSMB->Reserved2 = 0;
2811 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00002812 offsetof(struct smb_com_transaction2_qpi_req,
2813 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002814 pSMB->DataCount = 0;
2815 pSMB->DataOffset = 0;
2816 pSMB->SetupCount = 1;
2817 pSMB->Reserved3 = 0;
2818 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2819 byte_count = params + 1 /* pad */ ;
2820 pSMB->TotalParameterCount = cpu_to_le16(params);
2821 pSMB->ParameterCount = pSMB->TotalParameterCount;
2822 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2823 pSMB->Reserved4 = 0;
2824 pSMB->hdr.smb_buf_length += byte_count;
2825 pSMB->ByteCount = cpu_to_le16(byte_count);
2826
2827 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2828 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08002829 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002830 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002831 cFYI(1, "Send error in Query POSIX ACL = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832 } else {
2833 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00002834
Linus Torvalds1da177e2005-04-16 15:20:36 -07002835 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2836 if (rc || (pSMBr->ByteCount < 2))
2837 /* BB also check enough total bytes returned */
2838 rc = -EIO; /* bad smb */
2839 else {
2840 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2841 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2842 rc = cifs_copy_posix_acl(acl_inf,
2843 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00002844 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002845 }
2846 }
2847 cifs_buf_release(pSMB);
2848 if (rc == -EAGAIN)
2849 goto queryAclRetry;
2850 return rc;
2851}
2852
2853int
2854CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002855 const unsigned char *fileName,
2856 const char *local_acl, const int buflen,
2857 const int acl_type,
2858 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002859{
2860 struct smb_com_transaction2_spi_req *pSMB = NULL;
2861 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2862 char *parm_data;
2863 int name_len;
2864 int rc = 0;
2865 int bytes_returned = 0;
2866 __u16 params, byte_count, data_count, param_offset, offset;
2867
Joe Perchesb6b38f72010-04-21 03:50:45 +00002868 cFYI(1, "In SetPosixACL (Unix) for path %s", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002869setAclRetry:
2870 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002871 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002872 if (rc)
2873 return rc;
2874 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2875 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002876 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002877 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002878 name_len++; /* trailing null */
2879 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002880 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002881 name_len = strnlen(fileName, PATH_MAX);
2882 name_len++; /* trailing null */
2883 strncpy(pSMB->FileName, fileName, name_len);
2884 }
2885 params = 6 + name_len;
2886 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00002887 /* BB find max SMB size from sess */
2888 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002889 pSMB->MaxSetupCount = 0;
2890 pSMB->Reserved = 0;
2891 pSMB->Flags = 0;
2892 pSMB->Timeout = 0;
2893 pSMB->Reserved2 = 0;
2894 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002895 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002896 offset = param_offset + params;
2897 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2898 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2899
2900 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00002901 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002902
Steve French790fe572007-07-07 19:25:05 +00002903 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002904 rc = -EOPNOTSUPP;
2905 goto setACLerrorExit;
2906 }
2907 pSMB->DataOffset = cpu_to_le16(offset);
2908 pSMB->SetupCount = 1;
2909 pSMB->Reserved3 = 0;
2910 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2911 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2912 byte_count = 3 /* pad */ + params + data_count;
2913 pSMB->DataCount = cpu_to_le16(data_count);
2914 pSMB->TotalDataCount = pSMB->DataCount;
2915 pSMB->ParameterCount = cpu_to_le16(params);
2916 pSMB->TotalParameterCount = pSMB->ParameterCount;
2917 pSMB->Reserved4 = 0;
2918 pSMB->hdr.smb_buf_length += byte_count;
2919 pSMB->ByteCount = cpu_to_le16(byte_count);
2920 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002921 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00002922 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002923 cFYI(1, "Set POSIX ACL returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002924
2925setACLerrorExit:
2926 cifs_buf_release(pSMB);
2927 if (rc == -EAGAIN)
2928 goto setAclRetry;
2929 return rc;
2930}
2931
Steve Frenchf654bac2005-04-28 22:41:04 -07002932/* BB fix tabs in this function FIXME BB */
2933int
2934CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00002935 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07002936{
Steve French50c2f752007-07-13 00:33:32 +00002937 int rc = 0;
2938 struct smb_t2_qfi_req *pSMB = NULL;
2939 struct smb_t2_qfi_rsp *pSMBr = NULL;
2940 int bytes_returned;
2941 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07002942
Joe Perchesb6b38f72010-04-21 03:50:45 +00002943 cFYI(1, "In GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00002944 if (tcon == NULL)
2945 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07002946
2947GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00002948 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2949 (void **) &pSMBr);
2950 if (rc)
2951 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07002952
Steve Frenchad7a2922008-02-07 23:25:02 +00002953 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00002954 pSMB->t2.TotalDataCount = 0;
2955 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
2956 /* BB find exact max data count below from sess structure BB */
2957 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2958 pSMB->t2.MaxSetupCount = 0;
2959 pSMB->t2.Reserved = 0;
2960 pSMB->t2.Flags = 0;
2961 pSMB->t2.Timeout = 0;
2962 pSMB->t2.Reserved2 = 0;
2963 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2964 Fid) - 4);
2965 pSMB->t2.DataCount = 0;
2966 pSMB->t2.DataOffset = 0;
2967 pSMB->t2.SetupCount = 1;
2968 pSMB->t2.Reserved3 = 0;
2969 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2970 byte_count = params + 1 /* pad */ ;
2971 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2972 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2973 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
2974 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07002975 pSMB->Fid = netfid;
Steve French790fe572007-07-07 19:25:05 +00002976 pSMB->hdr.smb_buf_length += byte_count;
2977 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07002978
Steve French790fe572007-07-07 19:25:05 +00002979 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2980 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2981 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002982 cFYI(1, "error %d in GetExtAttr", rc);
Steve French790fe572007-07-07 19:25:05 +00002983 } else {
2984 /* decode response */
2985 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2986 if (rc || (pSMBr->ByteCount < 2))
2987 /* BB also check enough total bytes returned */
2988 /* If rc should we check for EOPNOSUPP and
2989 disable the srvino flag? or in caller? */
2990 rc = -EIO; /* bad smb */
2991 else {
2992 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2993 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2994 struct file_chattr_info *pfinfo;
2995 /* BB Do we need a cast or hash here ? */
2996 if (count != 16) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002997 cFYI(1, "Illegal size ret in GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00002998 rc = -EIO;
2999 goto GetExtAttrOut;
3000 }
3001 pfinfo = (struct file_chattr_info *)
3002 (data_offset + (char *) &pSMBr->hdr.Protocol);
3003 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003004 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003005 }
3006 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003007GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003008 cifs_buf_release(pSMB);
3009 if (rc == -EAGAIN)
3010 goto GetExtAttrRetry;
3011 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003012}
3013
Steve Frenchf654bac2005-04-28 22:41:04 -07003014#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003015
Jeff Layton79df1ba2010-12-06 12:52:08 -05003016#ifdef CONFIG_CIFS_ACL
3017/*
3018 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3019 * all NT TRANSACTS that we init here have total parm and data under about 400
3020 * bytes (to fit in small cifs buffer size), which is the case so far, it
3021 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3022 * returned setup area) and MaxParameterCount (returned parms size) must be set
3023 * by caller
3024 */
3025static int
3026smb_init_nttransact(const __u16 sub_command, const int setup_count,
3027 const int parm_len, struct cifsTconInfo *tcon,
3028 void **ret_buf)
3029{
3030 int rc;
3031 __u32 temp_offset;
3032 struct smb_com_ntransact_req *pSMB;
3033
3034 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3035 (void **)&pSMB);
3036 if (rc)
3037 return rc;
3038 *ret_buf = (void *)pSMB;
3039 pSMB->Reserved = 0;
3040 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3041 pSMB->TotalDataCount = 0;
3042 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
3043 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3044 pSMB->ParameterCount = pSMB->TotalParameterCount;
3045 pSMB->DataCount = pSMB->TotalDataCount;
3046 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3047 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3048 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3049 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3050 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3051 pSMB->SubCommand = cpu_to_le16(sub_command);
3052 return 0;
3053}
3054
3055static int
3056validate_ntransact(char *buf, char **ppparm, char **ppdata,
3057 __u32 *pparmlen, __u32 *pdatalen)
3058{
3059 char *end_of_smb;
3060 __u32 data_count, data_offset, parm_count, parm_offset;
3061 struct smb_com_ntransact_rsp *pSMBr;
3062
3063 *pdatalen = 0;
3064 *pparmlen = 0;
3065
3066 if (buf == NULL)
3067 return -EINVAL;
3068
3069 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3070
3071 /* ByteCount was converted from little endian in SendReceive */
3072 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
3073 (char *)&pSMBr->ByteCount;
3074
3075 data_offset = le32_to_cpu(pSMBr->DataOffset);
3076 data_count = le32_to_cpu(pSMBr->DataCount);
3077 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3078 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3079
3080 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3081 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3082
3083 /* should we also check that parm and data areas do not overlap? */
3084 if (*ppparm > end_of_smb) {
3085 cFYI(1, "parms start after end of smb");
3086 return -EINVAL;
3087 } else if (parm_count + *ppparm > end_of_smb) {
3088 cFYI(1, "parm end after end of smb");
3089 return -EINVAL;
3090 } else if (*ppdata > end_of_smb) {
3091 cFYI(1, "data starts after end of smb");
3092 return -EINVAL;
3093 } else if (data_count + *ppdata > end_of_smb) {
3094 cFYI(1, "data %p + count %d (%p) past smb end %p start %p",
3095 *ppdata, data_count, (data_count + *ppdata),
3096 end_of_smb, pSMBr);
3097 return -EINVAL;
3098 } else if (parm_count + data_count > pSMBr->ByteCount) {
3099 cFYI(1, "parm count and data count larger than SMB");
3100 return -EINVAL;
3101 }
3102 *pdatalen = data_count;
3103 *pparmlen = parm_count;
3104 return 0;
3105}
3106
Steve French0a4b92c2006-01-12 15:44:21 -08003107/* Get Security Descriptor (by handle) from remote server for a file or dir */
3108int
3109CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003110 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003111{
3112 int rc = 0;
3113 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003114 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003115 struct kvec iov[1];
3116
Joe Perchesb6b38f72010-04-21 03:50:45 +00003117 cFYI(1, "GetCifsACL");
Steve French0a4b92c2006-01-12 15:44:21 -08003118
Steve French630f3f0c2007-10-25 21:17:17 +00003119 *pbuflen = 0;
3120 *acl_inf = NULL;
3121
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003122 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003123 8 /* parm len */, tcon, (void **) &pSMB);
3124 if (rc)
3125 return rc;
3126
3127 pSMB->MaxParameterCount = cpu_to_le32(4);
3128 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3129 pSMB->MaxSetupCount = 0;
3130 pSMB->Fid = fid; /* file handle always le */
3131 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3132 CIFS_ACL_DACL);
3133 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
3134 pSMB->hdr.smb_buf_length += 11;
3135 iov[0].iov_base = (char *)pSMB;
3136 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
3137
Steve Frencha761ac52007-10-18 21:45:27 +00003138 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Steve French133672e2007-11-13 22:41:37 +00003139 CIFS_STD_OP);
Steve French0a4b92c2006-01-12 15:44:21 -08003140 cifs_stats_inc(&tcon->num_acl_get);
3141 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003142 cFYI(1, "Send error in QuerySecDesc = %d", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08003143 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003144 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003145 __u32 parm_len;
3146 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003147 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003148 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003149
3150/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003151 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003152 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003153 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003154 goto qsec_out;
3155 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3156
Joe Perchesb6b38f72010-04-21 03:50:45 +00003157 cFYI(1, "smb %p parm %p data %p", pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08003158
3159 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3160 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003161 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003162 goto qsec_out;
3163 }
3164
3165/* BB check that data area is minimum length and as big as acl_len */
3166
Steve Frenchaf6f4612007-10-16 18:40:37 +00003167 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003168 if (acl_len != *pbuflen) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003169 cERROR(1, "acl length %d does not match %d",
3170 acl_len, *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003171 if (*pbuflen > acl_len)
3172 *pbuflen = acl_len;
3173 }
Steve French0a4b92c2006-01-12 15:44:21 -08003174
Steve French630f3f0c2007-10-25 21:17:17 +00003175 /* check if buffer is big enough for the acl
3176 header followed by the smallest SID */
3177 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3178 (*pbuflen >= 64 * 1024)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003179 cERROR(1, "bad acl length %d", *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003180 rc = -EINVAL;
3181 *pbuflen = 0;
3182 } else {
3183 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3184 if (*acl_inf == NULL) {
3185 *pbuflen = 0;
3186 rc = -ENOMEM;
3187 }
3188 memcpy(*acl_inf, pdata, *pbuflen);
3189 }
Steve French0a4b92c2006-01-12 15:44:21 -08003190 }
3191qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003192 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003193 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003194 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003195 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003196/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003197 return rc;
3198}
Steve French97837582007-12-31 07:47:21 +00003199
3200int
3201CIFSSMBSetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3202 struct cifs_ntsd *pntsd, __u32 acllen)
3203{
3204 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3205 int rc = 0;
3206 int bytes_returned = 0;
3207 SET_SEC_DESC_REQ *pSMB = NULL;
3208 NTRANSACT_RSP *pSMBr = NULL;
3209
3210setCifsAclRetry:
3211 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB,
3212 (void **) &pSMBr);
3213 if (rc)
3214 return (rc);
3215
3216 pSMB->MaxSetupCount = 0;
3217 pSMB->Reserved = 0;
3218
3219 param_count = 8;
3220 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3221 data_count = acllen;
3222 data_offset = param_offset + param_count;
3223 byte_count = 3 /* pad */ + param_count;
3224
3225 pSMB->DataCount = cpu_to_le32(data_count);
3226 pSMB->TotalDataCount = pSMB->DataCount;
3227 pSMB->MaxParameterCount = cpu_to_le32(4);
3228 pSMB->MaxDataCount = cpu_to_le32(16384);
3229 pSMB->ParameterCount = cpu_to_le32(param_count);
3230 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3231 pSMB->TotalParameterCount = pSMB->ParameterCount;
3232 pSMB->DataOffset = cpu_to_le32(data_offset);
3233 pSMB->SetupCount = 0;
3234 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3235 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3236
3237 pSMB->Fid = fid; /* file handle always le */
3238 pSMB->Reserved2 = 0;
3239 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_DACL);
3240
3241 if (pntsd && acllen) {
3242 memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
3243 (char *) pntsd,
3244 acllen);
3245 pSMB->hdr.smb_buf_length += (byte_count + data_count);
3246
3247 } else
3248 pSMB->hdr.smb_buf_length += byte_count;
3249
3250 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3251 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3252
Joe Perchesb6b38f72010-04-21 03:50:45 +00003253 cFYI(1, "SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00003254 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003255 cFYI(1, "Set CIFS ACL returned %d", rc);
Steve French97837582007-12-31 07:47:21 +00003256 cifs_buf_release(pSMB);
3257
3258 if (rc == -EAGAIN)
3259 goto setCifsAclRetry;
3260
3261 return (rc);
3262}
3263
Jeff Layton79df1ba2010-12-06 12:52:08 -05003264#endif /* CONFIG_CIFS_ACL */
Steve French0a4b92c2006-01-12 15:44:21 -08003265
Steve French6b8edfe2005-08-23 20:26:03 -07003266/* Legacy Query Path Information call for lookup to old servers such
3267 as Win9x/WinME */
3268int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003269 const unsigned char *searchName,
3270 FILE_ALL_INFO *pFinfo,
3271 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003272{
Steve Frenchad7a2922008-02-07 23:25:02 +00003273 QUERY_INFORMATION_REQ *pSMB;
3274 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003275 int rc = 0;
3276 int bytes_returned;
3277 int name_len;
3278
Joe Perchesb6b38f72010-04-21 03:50:45 +00003279 cFYI(1, "In SMBQPath path %s", searchName);
Steve French6b8edfe2005-08-23 20:26:03 -07003280QInfRetry:
3281 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003282 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003283 if (rc)
3284 return rc;
3285
3286 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3287 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003288 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3289 PATH_MAX, nls_codepage, remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003290 name_len++; /* trailing null */
3291 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003292 } else {
Steve French6b8edfe2005-08-23 20:26:03 -07003293 name_len = strnlen(searchName, PATH_MAX);
3294 name_len++; /* trailing null */
3295 strncpy(pSMB->FileName, searchName, name_len);
3296 }
3297 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003298 name_len++; /* account for buffer type byte */
Steve French6b8edfe2005-08-23 20:26:03 -07003299 pSMB->hdr.smb_buf_length += (__u16) name_len;
3300 pSMB->ByteCount = cpu_to_le16(name_len);
3301
3302 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003303 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003304 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003305 cFYI(1, "Send error in QueryInfo = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00003306 } else if (pFinfo) {
Steve French1bd5bbc2006-09-28 03:35:57 +00003307 struct timespec ts;
3308 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00003309
3310 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003311 /* BB FIXME - add time zone adjustment BB */
Steve French6b8edfe2005-08-23 20:26:03 -07003312 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003313 ts.tv_nsec = 0;
3314 ts.tv_sec = time;
3315 /* decode time fields */
Al Viro733f99a2006-10-14 16:48:26 +01003316 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
Steve French1bd5bbc2006-09-28 03:35:57 +00003317 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3318 pFinfo->LastAccessTime = 0;
Steve French70ca7342005-09-22 16:32:06 -07003319 pFinfo->AllocationSize =
3320 cpu_to_le64(le32_to_cpu(pSMBr->size));
3321 pFinfo->EndOfFile = pFinfo->AllocationSize;
3322 pFinfo->Attributes =
3323 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003324 } else
3325 rc = -EIO; /* bad buffer passed in */
3326
3327 cifs_buf_release(pSMB);
3328
3329 if (rc == -EAGAIN)
3330 goto QInfRetry;
3331
3332 return rc;
3333}
3334
Jeff Laytonbcd53572010-02-12 07:44:16 -05003335int
3336CIFSSMBQFileInfo(const int xid, struct cifsTconInfo *tcon,
3337 u16 netfid, FILE_ALL_INFO *pFindData)
3338{
3339 struct smb_t2_qfi_req *pSMB = NULL;
3340 struct smb_t2_qfi_rsp *pSMBr = NULL;
3341 int rc = 0;
3342 int bytes_returned;
3343 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07003344
Jeff Laytonbcd53572010-02-12 07:44:16 -05003345QFileInfoRetry:
3346 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3347 (void **) &pSMBr);
3348 if (rc)
3349 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07003350
Jeff Laytonbcd53572010-02-12 07:44:16 -05003351 params = 2 /* level */ + 2 /* fid */;
3352 pSMB->t2.TotalDataCount = 0;
3353 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3354 /* BB find exact max data count below from sess structure BB */
3355 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3356 pSMB->t2.MaxSetupCount = 0;
3357 pSMB->t2.Reserved = 0;
3358 pSMB->t2.Flags = 0;
3359 pSMB->t2.Timeout = 0;
3360 pSMB->t2.Reserved2 = 0;
3361 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3362 Fid) - 4);
3363 pSMB->t2.DataCount = 0;
3364 pSMB->t2.DataOffset = 0;
3365 pSMB->t2.SetupCount = 1;
3366 pSMB->t2.Reserved3 = 0;
3367 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3368 byte_count = params + 1 /* pad */ ;
3369 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3370 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3371 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3372 pSMB->Pad = 0;
3373 pSMB->Fid = netfid;
3374 pSMB->hdr.smb_buf_length += byte_count;
3375
3376 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3377 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3378 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00003379 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003380 } else { /* decode response */
3381 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3382
3383 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3384 rc = -EIO;
3385 else if (pSMBr->ByteCount < 40)
3386 rc = -EIO; /* bad smb */
3387 else if (pFindData) {
3388 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3389 memcpy((char *) pFindData,
3390 (char *) &pSMBr->hdr.Protocol +
3391 data_offset, sizeof(FILE_ALL_INFO));
3392 } else
3393 rc = -ENOMEM;
3394 }
3395 cifs_buf_release(pSMB);
3396 if (rc == -EAGAIN)
3397 goto QFileInfoRetry;
3398
3399 return rc;
3400}
Steve French6b8edfe2005-08-23 20:26:03 -07003401
Linus Torvalds1da177e2005-04-16 15:20:36 -07003402int
3403CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3404 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003405 FILE_ALL_INFO *pFindData,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003406 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003407 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003408{
3409/* level 263 SMB_QUERY_FILE_ALL_INFO */
3410 TRANSACTION2_QPI_REQ *pSMB = NULL;
3411 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3412 int rc = 0;
3413 int bytes_returned;
3414 int name_len;
3415 __u16 params, byte_count;
3416
Joe Perchesb6b38f72010-04-21 03:50:45 +00003417/* cFYI(1, "In QPathInfo path %s", searchName); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003418QPathInfoRetry:
3419 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3420 (void **) &pSMBr);
3421 if (rc)
3422 return rc;
3423
3424 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3425 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003426 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003427 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003428 name_len++; /* trailing null */
3429 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003430 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003431 name_len = strnlen(searchName, PATH_MAX);
3432 name_len++; /* trailing null */
3433 strncpy(pSMB->FileName, searchName, name_len);
3434 }
3435
Steve French50c2f752007-07-13 00:33:32 +00003436 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003437 pSMB->TotalDataCount = 0;
3438 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003439 /* BB find exact max SMB PDU from sess structure BB */
3440 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003441 pSMB->MaxSetupCount = 0;
3442 pSMB->Reserved = 0;
3443 pSMB->Flags = 0;
3444 pSMB->Timeout = 0;
3445 pSMB->Reserved2 = 0;
3446 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003447 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003448 pSMB->DataCount = 0;
3449 pSMB->DataOffset = 0;
3450 pSMB->SetupCount = 1;
3451 pSMB->Reserved3 = 0;
3452 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3453 byte_count = params + 1 /* pad */ ;
3454 pSMB->TotalParameterCount = cpu_to_le16(params);
3455 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00003456 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003457 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3458 else
3459 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003460 pSMB->Reserved4 = 0;
3461 pSMB->hdr.smb_buf_length += byte_count;
3462 pSMB->ByteCount = cpu_to_le16(byte_count);
3463
3464 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3465 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3466 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003467 cFYI(1, "Send error in QPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003468 } else { /* decode response */
3469 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3470
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003471 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3472 rc = -EIO;
Steve French50c2f752007-07-13 00:33:32 +00003473 else if (!legacy && (pSMBr->ByteCount < 40))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003474 rc = -EIO; /* bad smb */
Steve French790fe572007-07-07 19:25:05 +00003475 else if (legacy && (pSMBr->ByteCount < 24))
Steve French50c2f752007-07-13 00:33:32 +00003476 rc = -EIO; /* 24 or 26 expected but we do not read
3477 last field */
3478 else if (pFindData) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003479 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003480 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00003481
3482 /* On legacy responses we do not read the last field,
3483 EAsize, fortunately since it varies by subdialect and
3484 also note it differs on Set vs. Get, ie two bytes or 4
3485 bytes depending but we don't care here */
3486 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003487 size = sizeof(FILE_INFO_STANDARD);
3488 else
3489 size = sizeof(FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003490 memcpy((char *) pFindData,
3491 (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003492 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003493 } else
3494 rc = -ENOMEM;
3495 }
3496 cifs_buf_release(pSMB);
3497 if (rc == -EAGAIN)
3498 goto QPathInfoRetry;
3499
3500 return rc;
3501}
3502
3503int
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003504CIFSSMBUnixQFileInfo(const int xid, struct cifsTconInfo *tcon,
3505 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
3506{
3507 struct smb_t2_qfi_req *pSMB = NULL;
3508 struct smb_t2_qfi_rsp *pSMBr = NULL;
3509 int rc = 0;
3510 int bytes_returned;
3511 __u16 params, byte_count;
3512
3513UnixQFileInfoRetry:
3514 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3515 (void **) &pSMBr);
3516 if (rc)
3517 return rc;
3518
3519 params = 2 /* level */ + 2 /* fid */;
3520 pSMB->t2.TotalDataCount = 0;
3521 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3522 /* BB find exact max data count below from sess structure BB */
3523 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3524 pSMB->t2.MaxSetupCount = 0;
3525 pSMB->t2.Reserved = 0;
3526 pSMB->t2.Flags = 0;
3527 pSMB->t2.Timeout = 0;
3528 pSMB->t2.Reserved2 = 0;
3529 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3530 Fid) - 4);
3531 pSMB->t2.DataCount = 0;
3532 pSMB->t2.DataOffset = 0;
3533 pSMB->t2.SetupCount = 1;
3534 pSMB->t2.Reserved3 = 0;
3535 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3536 byte_count = params + 1 /* pad */ ;
3537 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3538 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3539 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3540 pSMB->Pad = 0;
3541 pSMB->Fid = netfid;
3542 pSMB->hdr.smb_buf_length += byte_count;
3543
3544 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3545 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3546 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00003547 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003548 } else { /* decode response */
3549 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3550
3551 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
Steve Frenchf19159d2010-04-21 04:12:10 +00003552 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response.\n"
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003553 "Unix Extensions can be disabled on mount "
Steve Frenchf19159d2010-04-21 04:12:10 +00003554 "by specifying the nosfu mount option.");
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003555 rc = -EIO; /* bad smb */
3556 } else {
3557 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3558 memcpy((char *) pFindData,
3559 (char *) &pSMBr->hdr.Protocol +
3560 data_offset,
3561 sizeof(FILE_UNIX_BASIC_INFO));
3562 }
3563 }
3564
3565 cifs_buf_release(pSMB);
3566 if (rc == -EAGAIN)
3567 goto UnixQFileInfoRetry;
3568
3569 return rc;
3570}
3571
3572int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003573CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3574 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00003575 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07003576 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003577{
3578/* SMB_QUERY_FILE_UNIX_BASIC */
3579 TRANSACTION2_QPI_REQ *pSMB = NULL;
3580 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3581 int rc = 0;
3582 int bytes_returned = 0;
3583 int name_len;
3584 __u16 params, byte_count;
3585
Joe Perchesb6b38f72010-04-21 03:50:45 +00003586 cFYI(1, "In QPathInfo (Unix) the path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003587UnixQPathInfoRetry:
3588 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3589 (void **) &pSMBr);
3590 if (rc)
3591 return rc;
3592
3593 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3594 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003595 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003596 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003597 name_len++; /* trailing null */
3598 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003599 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003600 name_len = strnlen(searchName, PATH_MAX);
3601 name_len++; /* trailing null */
3602 strncpy(pSMB->FileName, searchName, name_len);
3603 }
3604
Steve French50c2f752007-07-13 00:33:32 +00003605 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003606 pSMB->TotalDataCount = 0;
3607 pSMB->MaxParameterCount = cpu_to_le16(2);
3608 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00003609 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003610 pSMB->MaxSetupCount = 0;
3611 pSMB->Reserved = 0;
3612 pSMB->Flags = 0;
3613 pSMB->Timeout = 0;
3614 pSMB->Reserved2 = 0;
3615 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003616 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003617 pSMB->DataCount = 0;
3618 pSMB->DataOffset = 0;
3619 pSMB->SetupCount = 1;
3620 pSMB->Reserved3 = 0;
3621 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3622 byte_count = params + 1 /* pad */ ;
3623 pSMB->TotalParameterCount = cpu_to_le16(params);
3624 pSMB->ParameterCount = pSMB->TotalParameterCount;
3625 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3626 pSMB->Reserved4 = 0;
3627 pSMB->hdr.smb_buf_length += byte_count;
3628 pSMB->ByteCount = cpu_to_le16(byte_count);
3629
3630 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3631 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3632 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003633 cFYI(1, "Send error in QPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003634 } else { /* decode response */
3635 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3636
3637 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003638 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response.\n"
Steve French1e71f252007-09-20 15:30:07 +00003639 "Unix Extensions can be disabled on mount "
Joe Perchesb6b38f72010-04-21 03:50:45 +00003640 "by specifying the nosfu mount option.");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003641 rc = -EIO; /* bad smb */
3642 } else {
3643 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3644 memcpy((char *) pFindData,
3645 (char *) &pSMBr->hdr.Protocol +
3646 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00003647 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003648 }
3649 }
3650 cifs_buf_release(pSMB);
3651 if (rc == -EAGAIN)
3652 goto UnixQPathInfoRetry;
3653
3654 return rc;
3655}
3656
Linus Torvalds1da177e2005-04-16 15:20:36 -07003657/* xid, tcon, searchName and codepage are input parms, rest are returned */
3658int
3659CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003660 const char *searchName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003661 const struct nls_table *nls_codepage,
Steve French50c2f752007-07-13 00:33:32 +00003662 __u16 *pnetfid,
3663 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003664{
3665/* level 257 SMB_ */
3666 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3667 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00003668 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003669 int rc = 0;
3670 int bytes_returned = 0;
3671 int name_len;
3672 __u16 params, byte_count;
3673
Joe Perchesb6b38f72010-04-21 03:50:45 +00003674 cFYI(1, "In FindFirst for %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003675
3676findFirstRetry:
3677 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3678 (void **) &pSMBr);
3679 if (rc)
3680 return rc;
3681
3682 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3683 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003684 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003685 PATH_MAX, nls_codepage, remap);
3686 /* We can not add the asterik earlier in case
3687 it got remapped to 0xF03A as if it were part of the
3688 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003689 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07003690 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07003691 pSMB->FileName[name_len+1] = 0;
3692 pSMB->FileName[name_len+2] = '*';
3693 pSMB->FileName[name_len+3] = 0;
3694 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003695 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3696 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07003697 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003698 } else { /* BB add check for overrun of SMB buf BB */
3699 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003700/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00003701 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003702 free buffer exit; BB */
3703 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07003704 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07003705 pSMB->FileName[name_len+1] = '*';
3706 pSMB->FileName[name_len+2] = 0;
3707 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003708 }
3709
3710 params = 12 + name_len /* includes null */ ;
3711 pSMB->TotalDataCount = 0; /* no EAs */
3712 pSMB->MaxParameterCount = cpu_to_le16(10);
3713 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3714 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3715 pSMB->MaxSetupCount = 0;
3716 pSMB->Reserved = 0;
3717 pSMB->Flags = 0;
3718 pSMB->Timeout = 0;
3719 pSMB->Reserved2 = 0;
3720 byte_count = params + 1 /* pad */ ;
3721 pSMB->TotalParameterCount = cpu_to_le16(params);
3722 pSMB->ParameterCount = pSMB->TotalParameterCount;
3723 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00003724 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3725 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003726 pSMB->DataCount = 0;
3727 pSMB->DataOffset = 0;
3728 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3729 pSMB->Reserved3 = 0;
3730 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3731 pSMB->SearchAttributes =
3732 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3733 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00003734 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3735 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
Linus Torvalds1da177e2005-04-16 15:20:36 -07003736 CIFS_SEARCH_RETURN_RESUME);
3737 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3738
3739 /* BB what should we set StorageType to? Does it matter? BB */
3740 pSMB->SearchStorageType = 0;
3741 pSMB->hdr.smb_buf_length += byte_count;
3742 pSMB->ByteCount = cpu_to_le16(byte_count);
3743
3744 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3745 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003746 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003747
Steve French88274812006-03-09 22:21:45 +00003748 if (rc) {/* BB add logic to retry regular search if Unix search
3749 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003750 /* BB Add code to handle unsupported level rc */
Joe Perchesb6b38f72010-04-21 03:50:45 +00003751 cFYI(1, "Error in FindFirst = %d", rc);
Steve French1982c342005-08-17 12:38:22 -07003752
Steve French88274812006-03-09 22:21:45 +00003753 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003754
3755 /* BB eventually could optimize out free and realloc of buf */
3756 /* for this case */
3757 if (rc == -EAGAIN)
3758 goto findFirstRetry;
3759 } else { /* decode response */
3760 /* BB remember to free buffer if error BB */
3761 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003762 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00003763 unsigned int lnoff;
3764
Linus Torvalds1da177e2005-04-16 15:20:36 -07003765 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00003766 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003767 else
Steve French4b18f2a2008-04-29 00:06:05 +00003768 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003769
3770 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003771 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00003772 psrch_inf->srch_entries_start =
3773 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003774 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003775 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3776 le16_to_cpu(pSMBr->t2.ParameterOffset));
3777
Steve French790fe572007-07-07 19:25:05 +00003778 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00003779 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003780 else
Steve French4b18f2a2008-04-29 00:06:05 +00003781 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003782
Steve French50c2f752007-07-13 00:33:32 +00003783 psrch_inf->entries_in_buffer =
3784 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00003785 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003786 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00003787 lnoff = le16_to_cpu(parms->LastNameOffset);
3788 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3789 lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003790 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00003791 psrch_inf->last_entry = NULL;
3792 return rc;
3793 }
3794
Steve French0752f152008-10-07 20:03:33 +00003795 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00003796 lnoff;
3797
Linus Torvalds1da177e2005-04-16 15:20:36 -07003798 *pnetfid = parms->SearchHandle;
3799 } else {
3800 cifs_buf_release(pSMB);
3801 }
3802 }
3803
3804 return rc;
3805}
3806
3807int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003808 __u16 searchHandle, struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003809{
3810 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3811 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00003812 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003813 char *response_data;
3814 int rc = 0;
3815 int bytes_returned, name_len;
3816 __u16 params, byte_count;
3817
Joe Perchesb6b38f72010-04-21 03:50:45 +00003818 cFYI(1, "In FindNext");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003819
Steve French4b18f2a2008-04-29 00:06:05 +00003820 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003821 return -ENOENT;
3822
3823 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3824 (void **) &pSMBr);
3825 if (rc)
3826 return rc;
3827
Steve French50c2f752007-07-13 00:33:32 +00003828 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003829 byte_count = 0;
3830 pSMB->TotalDataCount = 0; /* no EAs */
3831 pSMB->MaxParameterCount = cpu_to_le16(8);
3832 pSMB->MaxDataCount =
Steve French50c2f752007-07-13 00:33:32 +00003833 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
3834 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003835 pSMB->MaxSetupCount = 0;
3836 pSMB->Reserved = 0;
3837 pSMB->Flags = 0;
3838 pSMB->Timeout = 0;
3839 pSMB->Reserved2 = 0;
3840 pSMB->ParameterOffset = cpu_to_le16(
3841 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3842 pSMB->DataCount = 0;
3843 pSMB->DataOffset = 0;
3844 pSMB->SetupCount = 1;
3845 pSMB->Reserved3 = 0;
3846 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3847 pSMB->SearchHandle = searchHandle; /* always kept as le */
3848 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00003849 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003850 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3851 pSMB->ResumeKey = psrch_inf->resume_key;
3852 pSMB->SearchFlags =
3853 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3854
3855 name_len = psrch_inf->resume_name_len;
3856 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00003857 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003858 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3859 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07003860 /* 14 byte parm len above enough for 2 byte null terminator */
3861 pSMB->ResumeFileName[name_len] = 0;
3862 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003863 } else {
3864 rc = -EINVAL;
3865 goto FNext2_err_exit;
3866 }
3867 byte_count = params + 1 /* pad */ ;
3868 pSMB->TotalParameterCount = cpu_to_le16(params);
3869 pSMB->ParameterCount = pSMB->TotalParameterCount;
3870 pSMB->hdr.smb_buf_length += byte_count;
3871 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00003872
Linus Torvalds1da177e2005-04-16 15:20:36 -07003873 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3874 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003875 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003876 if (rc) {
3877 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00003878 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07003879 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00003880 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003881 } else
Joe Perchesb6b38f72010-04-21 03:50:45 +00003882 cFYI(1, "FindNext returned = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003883 } else { /* decode response */
3884 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00003885
Steve French790fe572007-07-07 19:25:05 +00003886 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00003887 unsigned int lnoff;
3888
Linus Torvalds1da177e2005-04-16 15:20:36 -07003889 /* BB fixme add lock for file (srch_info) struct here */
3890 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00003891 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003892 else
Steve French4b18f2a2008-04-29 00:06:05 +00003893 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003894 response_data = (char *) &pSMBr->hdr.Protocol +
3895 le16_to_cpu(pSMBr->t2.ParameterOffset);
3896 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3897 response_data = (char *)&pSMBr->hdr.Protocol +
3898 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00003899 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00003900 cifs_small_buf_release(
3901 psrch_inf->ntwrk_buf_start);
3902 else
3903 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003904 psrch_inf->srch_entries_start = response_data;
3905 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003906 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00003907 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00003908 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003909 else
Steve French4b18f2a2008-04-29 00:06:05 +00003910 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00003911 psrch_inf->entries_in_buffer =
3912 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003913 psrch_inf->index_of_last_entry +=
3914 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00003915 lnoff = le16_to_cpu(parms->LastNameOffset);
3916 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3917 lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003918 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00003919 psrch_inf->last_entry = NULL;
3920 return rc;
3921 } else
3922 psrch_inf->last_entry =
3923 psrch_inf->srch_entries_start + lnoff;
3924
Joe Perchesb6b38f72010-04-21 03:50:45 +00003925/* cFYI(1, "fnxt2 entries in buf %d index_of_last %d",
3926 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003927
3928 /* BB fixme add unlock here */
3929 }
3930
3931 }
3932
3933 /* BB On error, should we leave previous search buf (and count and
3934 last entry fields) intact or free the previous one? */
3935
3936 /* Note: On -EAGAIN error only caller can retry on handle based calls
3937 since file handle passed in no longer valid */
3938FNext2_err_exit:
3939 if (rc != 0)
3940 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003941 return rc;
3942}
3943
3944int
Steve French50c2f752007-07-13 00:33:32 +00003945CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
3946 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003947{
3948 int rc = 0;
3949 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003950
Joe Perchesb6b38f72010-04-21 03:50:45 +00003951 cFYI(1, "In CIFSSMBFindClose");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003952 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3953
3954 /* no sense returning error if session restarted
3955 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00003956 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003957 return 0;
3958 if (rc)
3959 return rc;
3960
Linus Torvalds1da177e2005-04-16 15:20:36 -07003961 pSMB->FileID = searchHandle;
3962 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00003963 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003964 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003965 cERROR(1, "Send error in FindClose = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00003966
Steve Frencha4544342005-08-24 13:59:35 -07003967 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003968
3969 /* Since session is dead, search handle closed on server already */
3970 if (rc == -EAGAIN)
3971 rc = 0;
3972
3973 return rc;
3974}
3975
Linus Torvalds1da177e2005-04-16 15:20:36 -07003976int
3977CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003978 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003979 __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00003980 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003981{
3982 int rc = 0;
3983 TRANSACTION2_QPI_REQ *pSMB = NULL;
3984 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3985 int name_len, bytes_returned;
3986 __u16 params, byte_count;
3987
Joe Perchesb6b38f72010-04-21 03:50:45 +00003988 cFYI(1, "In GetSrvInodeNum for %s", searchName);
Steve French790fe572007-07-07 19:25:05 +00003989 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00003990 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003991
3992GetInodeNumberRetry:
3993 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003994 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003995 if (rc)
3996 return rc;
3997
Linus Torvalds1da177e2005-04-16 15:20:36 -07003998 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3999 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004000 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French50c2f752007-07-13 00:33:32 +00004001 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004002 name_len++; /* trailing null */
4003 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004004 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004005 name_len = strnlen(searchName, PATH_MAX);
4006 name_len++; /* trailing null */
4007 strncpy(pSMB->FileName, searchName, name_len);
4008 }
4009
4010 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4011 pSMB->TotalDataCount = 0;
4012 pSMB->MaxParameterCount = cpu_to_le16(2);
4013 /* BB find exact max data count below from sess structure BB */
4014 pSMB->MaxDataCount = cpu_to_le16(4000);
4015 pSMB->MaxSetupCount = 0;
4016 pSMB->Reserved = 0;
4017 pSMB->Flags = 0;
4018 pSMB->Timeout = 0;
4019 pSMB->Reserved2 = 0;
4020 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004021 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004022 pSMB->DataCount = 0;
4023 pSMB->DataOffset = 0;
4024 pSMB->SetupCount = 1;
4025 pSMB->Reserved3 = 0;
4026 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4027 byte_count = params + 1 /* pad */ ;
4028 pSMB->TotalParameterCount = cpu_to_le16(params);
4029 pSMB->ParameterCount = pSMB->TotalParameterCount;
4030 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4031 pSMB->Reserved4 = 0;
4032 pSMB->hdr.smb_buf_length += byte_count;
4033 pSMB->ByteCount = cpu_to_le16(byte_count);
4034
4035 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4036 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4037 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004038 cFYI(1, "error %d in QueryInternalInfo", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004039 } else {
4040 /* decode response */
4041 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4042 if (rc || (pSMBr->ByteCount < 2))
4043 /* BB also check enough total bytes returned */
4044 /* If rc should we check for EOPNOSUPP and
4045 disable the srvino flag? or in caller? */
4046 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00004047 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004048 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4049 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00004050 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004051 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00004052 if (count < 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004053 cFYI(1, "Illegal size ret in QryIntrnlInf");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004054 rc = -EIO;
4055 goto GetInodeNumOut;
4056 }
4057 pfinfo = (struct file_internal_info *)
4058 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00004059 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004060 }
4061 }
4062GetInodeNumOut:
4063 cifs_buf_release(pSMB);
4064 if (rc == -EAGAIN)
4065 goto GetInodeNumberRetry;
4066 return rc;
4067}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004068
Igor Mammedovfec45852008-05-16 13:06:30 +04004069/* parses DFS refferal V3 structure
4070 * caller is responsible for freeing target_nodes
4071 * returns:
4072 * on success - 0
4073 * on failure - errno
4074 */
4075static int
Steve Frencha1fe78f2008-05-16 18:48:38 +00004076parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
Igor Mammedovfec45852008-05-16 13:06:30 +04004077 unsigned int *num_of_nodes,
4078 struct dfs_info3_param **target_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004079 const struct nls_table *nls_codepage, int remap,
4080 const char *searchName)
Igor Mammedovfec45852008-05-16 13:06:30 +04004081{
4082 int i, rc = 0;
4083 char *data_end;
4084 bool is_unicode;
4085 struct dfs_referral_level_3 *ref;
4086
Harvey Harrison5ca33c62008-07-23 17:45:58 -07004087 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4088 is_unicode = true;
4089 else
4090 is_unicode = false;
Igor Mammedovfec45852008-05-16 13:06:30 +04004091 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
4092
4093 if (*num_of_nodes < 1) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004094 cERROR(1, "num_referrals: must be at least > 0,"
4095 "but we get num_referrals = %d\n", *num_of_nodes);
Igor Mammedovfec45852008-05-16 13:06:30 +04004096 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004097 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004098 }
4099
4100 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
Al Viro1d92cfd2008-06-02 10:59:02 +01004101 if (ref->VersionNumber != cpu_to_le16(3)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004102 cERROR(1, "Referrals of V%d version are not supported,"
4103 "should be V3", le16_to_cpu(ref->VersionNumber));
Igor Mammedovfec45852008-05-16 13:06:30 +04004104 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004105 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004106 }
4107
4108 /* get the upper boundary of the resp buffer */
4109 data_end = (char *)(&(pSMBr->PathConsumed)) +
4110 le16_to_cpu(pSMBr->t2.DataCount);
4111
Steve Frenchf19159d2010-04-21 04:12:10 +00004112 cFYI(1, "num_referrals: %d dfs flags: 0x%x ...\n",
Igor Mammedovfec45852008-05-16 13:06:30 +04004113 *num_of_nodes,
Joe Perchesb6b38f72010-04-21 03:50:45 +00004114 le32_to_cpu(pSMBr->DFSFlags));
Igor Mammedovfec45852008-05-16 13:06:30 +04004115
4116 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
4117 *num_of_nodes, GFP_KERNEL);
4118 if (*target_nodes == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004119 cERROR(1, "Failed to allocate buffer for target_nodes\n");
Igor Mammedovfec45852008-05-16 13:06:30 +04004120 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004121 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004122 }
4123
Daniel Mack3ad2f3f2010-02-03 08:01:28 +08004124 /* collect necessary data from referrals */
Igor Mammedovfec45852008-05-16 13:06:30 +04004125 for (i = 0; i < *num_of_nodes; i++) {
4126 char *temp;
4127 int max_len;
4128 struct dfs_info3_param *node = (*target_nodes)+i;
4129
Steve French0e0d2cf2009-05-01 05:27:32 +00004130 node->flags = le32_to_cpu(pSMBr->DFSFlags);
Igor Mammedov2c556082008-10-23 13:58:42 +04004131 if (is_unicode) {
Jeff Layton331c3132008-12-17 06:31:53 -05004132 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4133 GFP_KERNEL);
Steve French2920ee22009-08-31 15:27:26 +00004134 if (tmp == NULL) {
4135 rc = -ENOMEM;
4136 goto parse_DFS_referrals_exit;
4137 }
Igor Mammedov2c556082008-10-23 13:58:42 +04004138 cifsConvertToUCS((__le16 *) tmp, searchName,
4139 PATH_MAX, nls_codepage, remap);
Jeff Layton69f801f2009-04-30 06:46:32 -04004140 node->path_consumed = cifs_ucs2_bytes(tmp,
4141 le16_to_cpu(pSMBr->PathConsumed),
Igor Mammedov2c556082008-10-23 13:58:42 +04004142 nls_codepage);
4143 kfree(tmp);
4144 } else
4145 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4146
Igor Mammedovfec45852008-05-16 13:06:30 +04004147 node->server_type = le16_to_cpu(ref->ServerType);
4148 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4149
4150 /* copy DfsPath */
4151 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4152 max_len = data_end - temp;
Steve Frenchd185cda2009-04-30 17:45:10 +00004153 node->path_name = cifs_strndup_from_ucs(temp, max_len,
4154 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004155 if (!node->path_name) {
4156 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004157 goto parse_DFS_referrals_exit;
Jeff Layton066ce682009-04-30 07:16:14 -04004158 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004159
4160 /* copy link target UNC */
4161 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4162 max_len = data_end - temp;
Steve Frenchd185cda2009-04-30 17:45:10 +00004163 node->node_name = cifs_strndup_from_ucs(temp, max_len,
4164 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004165 if (!node->node_name)
4166 rc = -ENOMEM;
Igor Mammedovfec45852008-05-16 13:06:30 +04004167 }
4168
Steve Frencha1fe78f2008-05-16 18:48:38 +00004169parse_DFS_referrals_exit:
Igor Mammedovfec45852008-05-16 13:06:30 +04004170 if (rc) {
4171 free_dfs_info_array(*target_nodes, *num_of_nodes);
4172 *target_nodes = NULL;
4173 *num_of_nodes = 0;
4174 }
4175 return rc;
4176}
4177
Linus Torvalds1da177e2005-04-16 15:20:36 -07004178int
4179CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
4180 const unsigned char *searchName,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004181 struct dfs_info3_param **target_nodes,
4182 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004183 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004184{
4185/* TRANS2_GET_DFS_REFERRAL */
4186 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4187 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004188 int rc = 0;
4189 int bytes_returned;
4190 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004191 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004192 *num_of_nodes = 0;
4193 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004194
Joe Perchesb6b38f72010-04-21 03:50:45 +00004195 cFYI(1, "In GetDFSRefer the path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004196 if (ses == NULL)
4197 return -ENODEV;
4198getDFSRetry:
4199 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4200 (void **) &pSMBr);
4201 if (rc)
4202 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004203
4204 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004205 but should never be null here anyway */
4206 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004207 pSMB->hdr.Tid = ses->ipc_tid;
4208 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004209 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004210 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004211 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004212 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004213
4214 if (ses->capabilities & CAP_UNICODE) {
4215 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4216 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004217 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07004218 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004219 name_len++; /* trailing null */
4220 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004221 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004222 name_len = strnlen(searchName, PATH_MAX);
4223 name_len++; /* trailing null */
4224 strncpy(pSMB->RequestFileName, searchName, name_len);
4225 }
4226
Steve French790fe572007-07-07 19:25:05 +00004227 if (ses->server) {
4228 if (ses->server->secMode &
Steve French1a4e15a2006-10-12 21:33:51 +00004229 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4230 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4231 }
4232
Steve French50c2f752007-07-13 00:33:32 +00004233 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004234
Linus Torvalds1da177e2005-04-16 15:20:36 -07004235 params = 2 /* level */ + name_len /*includes null */ ;
4236 pSMB->TotalDataCount = 0;
4237 pSMB->DataCount = 0;
4238 pSMB->DataOffset = 0;
4239 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004240 /* BB find exact max SMB PDU from sess structure BB */
4241 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004242 pSMB->MaxSetupCount = 0;
4243 pSMB->Reserved = 0;
4244 pSMB->Flags = 0;
4245 pSMB->Timeout = 0;
4246 pSMB->Reserved2 = 0;
4247 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004248 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004249 pSMB->SetupCount = 1;
4250 pSMB->Reserved3 = 0;
4251 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4252 byte_count = params + 3 /* pad */ ;
4253 pSMB->ParameterCount = cpu_to_le16(params);
4254 pSMB->TotalParameterCount = pSMB->ParameterCount;
4255 pSMB->MaxReferralLevel = cpu_to_le16(3);
4256 pSMB->hdr.smb_buf_length += byte_count;
4257 pSMB->ByteCount = cpu_to_le16(byte_count);
4258
4259 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4260 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4261 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004262 cFYI(1, "Send error in GetDFSRefer = %d", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004263 goto GetDFSRefExit;
4264 }
4265 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004266
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004267 /* BB Also check if enough total bytes returned? */
Igor Mammedovfec45852008-05-16 13:06:30 +04004268 if (rc || (pSMBr->ByteCount < 17)) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004269 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004270 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004271 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004272
Joe Perchesb6b38f72010-04-21 03:50:45 +00004273 cFYI(1, "Decoding GetDFSRefer response BCC: %d Offset %d",
Igor Mammedovfec45852008-05-16 13:06:30 +04004274 pSMBr->ByteCount,
Joe Perchesb6b38f72010-04-21 03:50:45 +00004275 le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04004276
4277 /* parse returned result into more usable form */
Steve Frencha1fe78f2008-05-16 18:48:38 +00004278 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004279 target_nodes, nls_codepage, remap,
4280 searchName);
Igor Mammedovfec45852008-05-16 13:06:30 +04004281
Linus Torvalds1da177e2005-04-16 15:20:36 -07004282GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004283 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004284
4285 if (rc == -EAGAIN)
4286 goto getDFSRetry;
4287
4288 return rc;
4289}
4290
Steve French20962432005-09-21 22:05:57 -07004291/* Query File System Info such as free space to old servers such as Win 9x */
4292int
4293SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4294{
4295/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4296 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4297 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4298 FILE_SYSTEM_ALLOC_INFO *response_data;
4299 int rc = 0;
4300 int bytes_returned = 0;
4301 __u16 params, byte_count;
4302
Joe Perchesb6b38f72010-04-21 03:50:45 +00004303 cFYI(1, "OldQFSInfo");
Steve French20962432005-09-21 22:05:57 -07004304oldQFSInfoRetry:
4305 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4306 (void **) &pSMBr);
4307 if (rc)
4308 return rc;
Steve French20962432005-09-21 22:05:57 -07004309
4310 params = 2; /* level */
4311 pSMB->TotalDataCount = 0;
4312 pSMB->MaxParameterCount = cpu_to_le16(2);
4313 pSMB->MaxDataCount = cpu_to_le16(1000);
4314 pSMB->MaxSetupCount = 0;
4315 pSMB->Reserved = 0;
4316 pSMB->Flags = 0;
4317 pSMB->Timeout = 0;
4318 pSMB->Reserved2 = 0;
4319 byte_count = params + 1 /* pad */ ;
4320 pSMB->TotalParameterCount = cpu_to_le16(params);
4321 pSMB->ParameterCount = pSMB->TotalParameterCount;
4322 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4323 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4324 pSMB->DataCount = 0;
4325 pSMB->DataOffset = 0;
4326 pSMB->SetupCount = 1;
4327 pSMB->Reserved3 = 0;
4328 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4329 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
4330 pSMB->hdr.smb_buf_length += byte_count;
4331 pSMB->ByteCount = cpu_to_le16(byte_count);
4332
4333 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4334 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4335 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004336 cFYI(1, "Send error in QFSInfo = %d", rc);
Steve French20962432005-09-21 22:05:57 -07004337 } else { /* decode response */
4338 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4339
4340 if (rc || (pSMBr->ByteCount < 18))
4341 rc = -EIO; /* bad smb */
4342 else {
4343 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004344 cFYI(1, "qfsinf resp BCC: %d Offset %d",
4345 pSMBr->ByteCount, data_offset);
Steve French20962432005-09-21 22:05:57 -07004346
Steve French50c2f752007-07-13 00:33:32 +00004347 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004348 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4349 FSData->f_bsize =
4350 le16_to_cpu(response_data->BytesPerSector) *
4351 le32_to_cpu(response_data->
4352 SectorsPerAllocationUnit);
4353 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004354 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004355 FSData->f_bfree = FSData->f_bavail =
4356 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004357 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
4358 (unsigned long long)FSData->f_blocks,
4359 (unsigned long long)FSData->f_bfree,
4360 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07004361 }
4362 }
4363 cifs_buf_release(pSMB);
4364
4365 if (rc == -EAGAIN)
4366 goto oldQFSInfoRetry;
4367
4368 return rc;
4369}
4370
Linus Torvalds1da177e2005-04-16 15:20:36 -07004371int
Steve French737b7582005-04-28 22:41:06 -07004372CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004373{
4374/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4375 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4376 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4377 FILE_SYSTEM_INFO *response_data;
4378 int rc = 0;
4379 int bytes_returned = 0;
4380 __u16 params, byte_count;
4381
Joe Perchesb6b38f72010-04-21 03:50:45 +00004382 cFYI(1, "In QFSInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004383QFSInfoRetry:
4384 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4385 (void **) &pSMBr);
4386 if (rc)
4387 return rc;
4388
4389 params = 2; /* level */
4390 pSMB->TotalDataCount = 0;
4391 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004392 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004393 pSMB->MaxSetupCount = 0;
4394 pSMB->Reserved = 0;
4395 pSMB->Flags = 0;
4396 pSMB->Timeout = 0;
4397 pSMB->Reserved2 = 0;
4398 byte_count = params + 1 /* pad */ ;
4399 pSMB->TotalParameterCount = cpu_to_le16(params);
4400 pSMB->ParameterCount = pSMB->TotalParameterCount;
4401 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004402 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004403 pSMB->DataCount = 0;
4404 pSMB->DataOffset = 0;
4405 pSMB->SetupCount = 1;
4406 pSMB->Reserved3 = 0;
4407 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4408 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
4409 pSMB->hdr.smb_buf_length += byte_count;
4410 pSMB->ByteCount = cpu_to_le16(byte_count);
4411
4412 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4413 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4414 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004415 cFYI(1, "Send error in QFSInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004416 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00004417 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004418
Steve French20962432005-09-21 22:05:57 -07004419 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004420 rc = -EIO; /* bad smb */
4421 else {
4422 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004423
4424 response_data =
4425 (FILE_SYSTEM_INFO
4426 *) (((char *) &pSMBr->hdr.Protocol) +
4427 data_offset);
4428 FSData->f_bsize =
4429 le32_to_cpu(response_data->BytesPerSector) *
4430 le32_to_cpu(response_data->
4431 SectorsPerAllocationUnit);
4432 FSData->f_blocks =
4433 le64_to_cpu(response_data->TotalAllocationUnits);
4434 FSData->f_bfree = FSData->f_bavail =
4435 le64_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004436 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
4437 (unsigned long long)FSData->f_blocks,
4438 (unsigned long long)FSData->f_bfree,
4439 FSData->f_bsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004440 }
4441 }
4442 cifs_buf_release(pSMB);
4443
4444 if (rc == -EAGAIN)
4445 goto QFSInfoRetry;
4446
4447 return rc;
4448}
4449
4450int
Steve French737b7582005-04-28 22:41:06 -07004451CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004452{
4453/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4454 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4455 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4456 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4457 int rc = 0;
4458 int bytes_returned = 0;
4459 __u16 params, byte_count;
4460
Joe Perchesb6b38f72010-04-21 03:50:45 +00004461 cFYI(1, "In QFSAttributeInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004462QFSAttributeRetry:
4463 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4464 (void **) &pSMBr);
4465 if (rc)
4466 return rc;
4467
4468 params = 2; /* level */
4469 pSMB->TotalDataCount = 0;
4470 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004471 /* BB find exact max SMB PDU from sess structure BB */
4472 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004473 pSMB->MaxSetupCount = 0;
4474 pSMB->Reserved = 0;
4475 pSMB->Flags = 0;
4476 pSMB->Timeout = 0;
4477 pSMB->Reserved2 = 0;
4478 byte_count = params + 1 /* pad */ ;
4479 pSMB->TotalParameterCount = cpu_to_le16(params);
4480 pSMB->ParameterCount = pSMB->TotalParameterCount;
4481 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004482 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004483 pSMB->DataCount = 0;
4484 pSMB->DataOffset = 0;
4485 pSMB->SetupCount = 1;
4486 pSMB->Reserved3 = 0;
4487 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4488 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4489 pSMB->hdr.smb_buf_length += byte_count;
4490 pSMB->ByteCount = cpu_to_le16(byte_count);
4491
4492 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4493 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4494 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004495 cERROR(1, "Send error in QFSAttributeInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004496 } else { /* decode response */
4497 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4498
Steve French50c2f752007-07-13 00:33:32 +00004499 if (rc || (pSMBr->ByteCount < 13)) {
4500 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004501 rc = -EIO; /* bad smb */
4502 } else {
4503 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4504 response_data =
4505 (FILE_SYSTEM_ATTRIBUTE_INFO
4506 *) (((char *) &pSMBr->hdr.Protocol) +
4507 data_offset);
4508 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004509 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004510 }
4511 }
4512 cifs_buf_release(pSMB);
4513
4514 if (rc == -EAGAIN)
4515 goto QFSAttributeRetry;
4516
4517 return rc;
4518}
4519
4520int
Steve French737b7582005-04-28 22:41:06 -07004521CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004522{
4523/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4524 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4525 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4526 FILE_SYSTEM_DEVICE_INFO *response_data;
4527 int rc = 0;
4528 int bytes_returned = 0;
4529 __u16 params, byte_count;
4530
Joe Perchesb6b38f72010-04-21 03:50:45 +00004531 cFYI(1, "In QFSDeviceInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004532QFSDeviceRetry:
4533 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4534 (void **) &pSMBr);
4535 if (rc)
4536 return rc;
4537
4538 params = 2; /* level */
4539 pSMB->TotalDataCount = 0;
4540 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004541 /* BB find exact max SMB PDU from sess structure BB */
4542 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004543 pSMB->MaxSetupCount = 0;
4544 pSMB->Reserved = 0;
4545 pSMB->Flags = 0;
4546 pSMB->Timeout = 0;
4547 pSMB->Reserved2 = 0;
4548 byte_count = params + 1 /* pad */ ;
4549 pSMB->TotalParameterCount = cpu_to_le16(params);
4550 pSMB->ParameterCount = pSMB->TotalParameterCount;
4551 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004552 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004553
4554 pSMB->DataCount = 0;
4555 pSMB->DataOffset = 0;
4556 pSMB->SetupCount = 1;
4557 pSMB->Reserved3 = 0;
4558 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4559 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4560 pSMB->hdr.smb_buf_length += byte_count;
4561 pSMB->ByteCount = cpu_to_le16(byte_count);
4562
4563 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4564 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4565 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004566 cFYI(1, "Send error in QFSDeviceInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004567 } else { /* decode response */
4568 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4569
Steve French630f3f0c2007-10-25 21:17:17 +00004570 if (rc || (pSMBr->ByteCount < sizeof(FILE_SYSTEM_DEVICE_INFO)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004571 rc = -EIO; /* bad smb */
4572 else {
4573 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4574 response_data =
Steve French737b7582005-04-28 22:41:06 -07004575 (FILE_SYSTEM_DEVICE_INFO *)
4576 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004577 data_offset);
4578 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004579 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004580 }
4581 }
4582 cifs_buf_release(pSMB);
4583
4584 if (rc == -EAGAIN)
4585 goto QFSDeviceRetry;
4586
4587 return rc;
4588}
4589
4590int
Steve French737b7582005-04-28 22:41:06 -07004591CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004592{
4593/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4594 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4595 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4596 FILE_SYSTEM_UNIX_INFO *response_data;
4597 int rc = 0;
4598 int bytes_returned = 0;
4599 __u16 params, byte_count;
4600
Joe Perchesb6b38f72010-04-21 03:50:45 +00004601 cFYI(1, "In QFSUnixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004602QFSUnixRetry:
Jeff Laytonf5695992010-09-29 15:27:08 -04004603 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
4604 (void **) &pSMB, (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004605 if (rc)
4606 return rc;
4607
4608 params = 2; /* level */
4609 pSMB->TotalDataCount = 0;
4610 pSMB->DataCount = 0;
4611 pSMB->DataOffset = 0;
4612 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004613 /* BB find exact max SMB PDU from sess structure BB */
4614 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004615 pSMB->MaxSetupCount = 0;
4616 pSMB->Reserved = 0;
4617 pSMB->Flags = 0;
4618 pSMB->Timeout = 0;
4619 pSMB->Reserved2 = 0;
4620 byte_count = params + 1 /* pad */ ;
4621 pSMB->ParameterCount = cpu_to_le16(params);
4622 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004623 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4624 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004625 pSMB->SetupCount = 1;
4626 pSMB->Reserved3 = 0;
4627 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4628 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4629 pSMB->hdr.smb_buf_length += byte_count;
4630 pSMB->ByteCount = cpu_to_le16(byte_count);
4631
4632 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4633 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4634 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004635 cERROR(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004636 } else { /* decode response */
4637 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4638
4639 if (rc || (pSMBr->ByteCount < 13)) {
4640 rc = -EIO; /* bad smb */
4641 } else {
4642 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4643 response_data =
4644 (FILE_SYSTEM_UNIX_INFO
4645 *) (((char *) &pSMBr->hdr.Protocol) +
4646 data_offset);
4647 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004648 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004649 }
4650 }
4651 cifs_buf_release(pSMB);
4652
4653 if (rc == -EAGAIN)
4654 goto QFSUnixRetry;
4655
4656
4657 return rc;
4658}
4659
Jeremy Allisonac670552005-06-22 17:26:35 -07004660int
Steve French45abc6e2005-06-23 13:42:03 -05004661CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07004662{
4663/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4664 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4665 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4666 int rc = 0;
4667 int bytes_returned = 0;
4668 __u16 params, param_offset, offset, byte_count;
4669
Joe Perchesb6b38f72010-04-21 03:50:45 +00004670 cFYI(1, "In SETFSUnixInfo");
Jeremy Allisonac670552005-06-22 17:26:35 -07004671SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00004672 /* BB switch to small buf init to save memory */
Jeff Laytonf5695992010-09-29 15:27:08 -04004673 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
4674 (void **) &pSMB, (void **) &pSMBr);
Jeremy Allisonac670552005-06-22 17:26:35 -07004675 if (rc)
4676 return rc;
4677
4678 params = 4; /* 2 bytes zero followed by info level. */
4679 pSMB->MaxSetupCount = 0;
4680 pSMB->Reserved = 0;
4681 pSMB->Flags = 0;
4682 pSMB->Timeout = 0;
4683 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00004684 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4685 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07004686 offset = param_offset + params;
4687
4688 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00004689 /* BB find exact max SMB PDU from sess structure BB */
4690 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07004691 pSMB->SetupCount = 1;
4692 pSMB->Reserved3 = 0;
4693 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4694 byte_count = 1 /* pad */ + params + 12;
4695
4696 pSMB->DataCount = cpu_to_le16(12);
4697 pSMB->ParameterCount = cpu_to_le16(params);
4698 pSMB->TotalDataCount = pSMB->DataCount;
4699 pSMB->TotalParameterCount = pSMB->ParameterCount;
4700 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4701 pSMB->DataOffset = cpu_to_le16(offset);
4702
4703 /* Params. */
4704 pSMB->FileNum = 0;
4705 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4706
4707 /* Data. */
4708 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4709 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4710 pSMB->ClientUnixCap = cpu_to_le64(cap);
4711
4712 pSMB->hdr.smb_buf_length += byte_count;
4713 pSMB->ByteCount = cpu_to_le16(byte_count);
4714
4715 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4716 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4717 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004718 cERROR(1, "Send error in SETFSUnixInfo = %d", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07004719 } else { /* decode response */
4720 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00004721 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07004722 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07004723 }
4724 cifs_buf_release(pSMB);
4725
4726 if (rc == -EAGAIN)
4727 goto SETFSUnixRetry;
4728
4729 return rc;
4730}
4731
4732
Linus Torvalds1da177e2005-04-16 15:20:36 -07004733
4734int
4735CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004736 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004737{
4738/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4739 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4740 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4741 FILE_SYSTEM_POSIX_INFO *response_data;
4742 int rc = 0;
4743 int bytes_returned = 0;
4744 __u16 params, byte_count;
4745
Joe Perchesb6b38f72010-04-21 03:50:45 +00004746 cFYI(1, "In QFSPosixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004747QFSPosixRetry:
4748 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4749 (void **) &pSMBr);
4750 if (rc)
4751 return rc;
4752
4753 params = 2; /* level */
4754 pSMB->TotalDataCount = 0;
4755 pSMB->DataCount = 0;
4756 pSMB->DataOffset = 0;
4757 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004758 /* BB find exact max SMB PDU from sess structure BB */
4759 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004760 pSMB->MaxSetupCount = 0;
4761 pSMB->Reserved = 0;
4762 pSMB->Flags = 0;
4763 pSMB->Timeout = 0;
4764 pSMB->Reserved2 = 0;
4765 byte_count = params + 1 /* pad */ ;
4766 pSMB->ParameterCount = cpu_to_le16(params);
4767 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004768 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4769 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004770 pSMB->SetupCount = 1;
4771 pSMB->Reserved3 = 0;
4772 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4773 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4774 pSMB->hdr.smb_buf_length += byte_count;
4775 pSMB->ByteCount = cpu_to_le16(byte_count);
4776
4777 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4778 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4779 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004780 cFYI(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004781 } else { /* decode response */
4782 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4783
4784 if (rc || (pSMBr->ByteCount < 13)) {
4785 rc = -EIO; /* bad smb */
4786 } else {
4787 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4788 response_data =
4789 (FILE_SYSTEM_POSIX_INFO
4790 *) (((char *) &pSMBr->hdr.Protocol) +
4791 data_offset);
4792 FSData->f_bsize =
4793 le32_to_cpu(response_data->BlockSize);
4794 FSData->f_blocks =
4795 le64_to_cpu(response_data->TotalBlocks);
4796 FSData->f_bfree =
4797 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00004798 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004799 FSData->f_bavail = FSData->f_bfree;
4800 } else {
4801 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00004802 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004803 }
Steve French790fe572007-07-07 19:25:05 +00004804 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004805 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00004806 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00004807 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004808 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00004809 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004810 }
4811 }
4812 cifs_buf_release(pSMB);
4813
4814 if (rc == -EAGAIN)
4815 goto QFSPosixRetry;
4816
4817 return rc;
4818}
4819
4820
Steve French50c2f752007-07-13 00:33:32 +00004821/* We can not use write of zero bytes trick to
4822 set file size due to need for large file support. Also note that
4823 this SetPathInfo is preferred to SetFileInfo based method in next
Linus Torvalds1da177e2005-04-16 15:20:36 -07004824 routine which is only needed to work around a sharing violation bug
4825 in Samba which this routine can run into */
4826
4827int
4828CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French4b18f2a2008-04-29 00:06:05 +00004829 __u64 size, bool SetAllocation,
Steve French737b7582005-04-28 22:41:06 -07004830 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004831{
4832 struct smb_com_transaction2_spi_req *pSMB = NULL;
4833 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4834 struct file_end_of_file_info *parm_data;
4835 int name_len;
4836 int rc = 0;
4837 int bytes_returned = 0;
4838 __u16 params, byte_count, data_count, param_offset, offset;
4839
Joe Perchesb6b38f72010-04-21 03:50:45 +00004840 cFYI(1, "In SetEOF");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004841SetEOFRetry:
4842 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4843 (void **) &pSMBr);
4844 if (rc)
4845 return rc;
4846
4847 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4848 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004849 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004850 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004851 name_len++; /* trailing null */
4852 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004853 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004854 name_len = strnlen(fileName, PATH_MAX);
4855 name_len++; /* trailing null */
4856 strncpy(pSMB->FileName, fileName, name_len);
4857 }
4858 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00004859 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004860 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07004861 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004862 pSMB->MaxSetupCount = 0;
4863 pSMB->Reserved = 0;
4864 pSMB->Flags = 0;
4865 pSMB->Timeout = 0;
4866 pSMB->Reserved2 = 0;
4867 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00004868 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004869 offset = param_offset + params;
Steve French790fe572007-07-07 19:25:05 +00004870 if (SetAllocation) {
Steve French50c2f752007-07-13 00:33:32 +00004871 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4872 pSMB->InformationLevel =
4873 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4874 else
4875 pSMB->InformationLevel =
4876 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4877 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004878 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4879 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004880 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004881 else
4882 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004883 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004884 }
4885
4886 parm_data =
4887 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4888 offset);
4889 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4890 pSMB->DataOffset = cpu_to_le16(offset);
4891 pSMB->SetupCount = 1;
4892 pSMB->Reserved3 = 0;
4893 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4894 byte_count = 3 /* pad */ + params + data_count;
4895 pSMB->DataCount = cpu_to_le16(data_count);
4896 pSMB->TotalDataCount = pSMB->DataCount;
4897 pSMB->ParameterCount = cpu_to_le16(params);
4898 pSMB->TotalParameterCount = pSMB->ParameterCount;
4899 pSMB->Reserved4 = 0;
4900 pSMB->hdr.smb_buf_length += byte_count;
4901 parm_data->FileSize = cpu_to_le64(size);
4902 pSMB->ByteCount = cpu_to_le16(byte_count);
4903 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4904 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004905 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00004906 cFYI(1, "SetPathInfo (file size) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004907
4908 cifs_buf_release(pSMB);
4909
4910 if (rc == -EAGAIN)
4911 goto SetEOFRetry;
4912
4913 return rc;
4914}
4915
4916int
Steve French50c2f752007-07-13 00:33:32 +00004917CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
Steve French4b18f2a2008-04-29 00:06:05 +00004918 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004919{
4920 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004921 char *data_offset;
4922 struct file_end_of_file_info *parm_data;
4923 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004924 __u16 params, param_offset, offset, byte_count, count;
4925
Joe Perchesb6b38f72010-04-21 03:50:45 +00004926 cFYI(1, "SetFileSize (via SetFileInfo) %lld",
4927 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07004928 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4929
Linus Torvalds1da177e2005-04-16 15:20:36 -07004930 if (rc)
4931 return rc;
4932
4933 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4934 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00004935
Linus Torvalds1da177e2005-04-16 15:20:36 -07004936 params = 6;
4937 pSMB->MaxSetupCount = 0;
4938 pSMB->Reserved = 0;
4939 pSMB->Flags = 0;
4940 pSMB->Timeout = 0;
4941 pSMB->Reserved2 = 0;
4942 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4943 offset = param_offset + params;
4944
Steve French50c2f752007-07-13 00:33:32 +00004945 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004946
4947 count = sizeof(struct file_end_of_file_info);
4948 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004949 /* BB find exact max SMB PDU from sess structure BB */
4950 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004951 pSMB->SetupCount = 1;
4952 pSMB->Reserved3 = 0;
4953 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4954 byte_count = 3 /* pad */ + params + count;
4955 pSMB->DataCount = cpu_to_le16(count);
4956 pSMB->ParameterCount = cpu_to_le16(params);
4957 pSMB->TotalDataCount = pSMB->DataCount;
4958 pSMB->TotalParameterCount = pSMB->ParameterCount;
4959 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4960 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00004961 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
4962 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004963 pSMB->DataOffset = cpu_to_le16(offset);
4964 parm_data->FileSize = cpu_to_le64(size);
4965 pSMB->Fid = fid;
Steve French790fe572007-07-07 19:25:05 +00004966 if (SetAllocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004967 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4968 pSMB->InformationLevel =
4969 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4970 else
4971 pSMB->InformationLevel =
4972 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00004973 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004974 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4975 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004976 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004977 else
4978 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004979 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004980 }
4981 pSMB->Reserved4 = 0;
4982 pSMB->hdr.smb_buf_length += byte_count;
4983 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French133672e2007-11-13 22:41:37 +00004984 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004985 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004986 cFYI(1, "Send error in SetFileInfo (SetFileSize) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004987 }
4988
Steve French50c2f752007-07-13 00:33:32 +00004989 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004990 since file handle passed in no longer valid */
4991
4992 return rc;
4993}
4994
Steve French50c2f752007-07-13 00:33:32 +00004995/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07004996 an open handle, rather than by pathname - this is awkward due to
4997 potential access conflicts on the open, but it is unavoidable for these
4998 old servers since the only other choice is to go from 100 nanosecond DCE
4999 time and resort to the original setpathinfo level which takes the ancient
5000 DOS time format with 2 second granularity */
5001int
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005002CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon,
5003 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005004{
5005 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005006 char *data_offset;
5007 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005008 __u16 params, param_offset, offset, byte_count, count;
5009
Joe Perchesb6b38f72010-04-21 03:50:45 +00005010 cFYI(1, "Set Times (via SetFileInfo)");
Steve Frenchcd634992005-04-28 22:41:10 -07005011 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5012
Linus Torvalds1da177e2005-04-16 15:20:36 -07005013 if (rc)
5014 return rc;
5015
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005016 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5017 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005018
Linus Torvalds1da177e2005-04-16 15:20:36 -07005019 params = 6;
5020 pSMB->MaxSetupCount = 0;
5021 pSMB->Reserved = 0;
5022 pSMB->Flags = 0;
5023 pSMB->Timeout = 0;
5024 pSMB->Reserved2 = 0;
5025 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5026 offset = param_offset + params;
5027
Steve French50c2f752007-07-13 00:33:32 +00005028 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005029
Steve French26f57362007-08-30 22:09:15 +00005030 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005031 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005032 /* BB find max SMB PDU from sess */
5033 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005034 pSMB->SetupCount = 1;
5035 pSMB->Reserved3 = 0;
5036 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5037 byte_count = 3 /* pad */ + params + count;
5038 pSMB->DataCount = cpu_to_le16(count);
5039 pSMB->ParameterCount = cpu_to_le16(params);
5040 pSMB->TotalDataCount = pSMB->DataCount;
5041 pSMB->TotalParameterCount = pSMB->ParameterCount;
5042 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5043 pSMB->DataOffset = cpu_to_le16(offset);
5044 pSMB->Fid = fid;
5045 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5046 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5047 else
5048 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5049 pSMB->Reserved4 = 0;
5050 pSMB->hdr.smb_buf_length += byte_count;
5051 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005052 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Steve French133672e2007-11-13 22:41:37 +00005053 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005054 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005055 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005056
Steve French50c2f752007-07-13 00:33:32 +00005057 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005058 since file handle passed in no longer valid */
5059
5060 return rc;
5061}
5062
Jeff Layton6d22f092008-09-23 11:48:35 -04005063int
5064CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon,
5065 bool delete_file, __u16 fid, __u32 pid_of_opener)
5066{
5067 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5068 char *data_offset;
5069 int rc = 0;
5070 __u16 params, param_offset, offset, byte_count, count;
5071
Joe Perchesb6b38f72010-04-21 03:50:45 +00005072 cFYI(1, "Set File Disposition (via SetFileInfo)");
Jeff Layton6d22f092008-09-23 11:48:35 -04005073 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5074
5075 if (rc)
5076 return rc;
5077
5078 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5079 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5080
5081 params = 6;
5082 pSMB->MaxSetupCount = 0;
5083 pSMB->Reserved = 0;
5084 pSMB->Flags = 0;
5085 pSMB->Timeout = 0;
5086 pSMB->Reserved2 = 0;
5087 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5088 offset = param_offset + params;
5089
5090 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5091
5092 count = 1;
5093 pSMB->MaxParameterCount = cpu_to_le16(2);
5094 /* BB find max SMB PDU from sess */
5095 pSMB->MaxDataCount = cpu_to_le16(1000);
5096 pSMB->SetupCount = 1;
5097 pSMB->Reserved3 = 0;
5098 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5099 byte_count = 3 /* pad */ + params + count;
5100 pSMB->DataCount = cpu_to_le16(count);
5101 pSMB->ParameterCount = cpu_to_le16(params);
5102 pSMB->TotalDataCount = pSMB->DataCount;
5103 pSMB->TotalParameterCount = pSMB->ParameterCount;
5104 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5105 pSMB->DataOffset = cpu_to_le16(offset);
5106 pSMB->Fid = fid;
5107 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5108 pSMB->Reserved4 = 0;
5109 pSMB->hdr.smb_buf_length += byte_count;
5110 pSMB->ByteCount = cpu_to_le16(byte_count);
5111 *data_offset = delete_file ? 1 : 0;
5112 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
5113 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005114 cFYI(1, "Send error in SetFileDisposition = %d", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005115
5116 return rc;
5117}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005118
5119int
Jeff Layton6fc000e2008-08-02 07:26:12 -04005120CIFSSMBSetPathInfo(const int xid, struct cifsTconInfo *tcon,
5121 const char *fileName, const FILE_BASIC_INFO *data,
5122 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005123{
5124 TRANSACTION2_SPI_REQ *pSMB = NULL;
5125 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5126 int name_len;
5127 int rc = 0;
5128 int bytes_returned = 0;
5129 char *data_offset;
5130 __u16 params, param_offset, offset, byte_count, count;
5131
Joe Perchesb6b38f72010-04-21 03:50:45 +00005132 cFYI(1, "In SetTimes");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005133
5134SetTimesRetry:
5135 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5136 (void **) &pSMBr);
5137 if (rc)
5138 return rc;
5139
5140 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5141 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05005142 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005143 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005144 name_len++; /* trailing null */
5145 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005146 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005147 name_len = strnlen(fileName, PATH_MAX);
5148 name_len++; /* trailing null */
5149 strncpy(pSMB->FileName, fileName, name_len);
5150 }
5151
5152 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005153 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005154 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005155 /* BB find max SMB PDU from sess structure BB */
5156 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005157 pSMB->MaxSetupCount = 0;
5158 pSMB->Reserved = 0;
5159 pSMB->Flags = 0;
5160 pSMB->Timeout = 0;
5161 pSMB->Reserved2 = 0;
5162 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005163 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005164 offset = param_offset + params;
5165 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5166 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5167 pSMB->DataOffset = cpu_to_le16(offset);
5168 pSMB->SetupCount = 1;
5169 pSMB->Reserved3 = 0;
5170 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5171 byte_count = 3 /* pad */ + params + count;
5172
5173 pSMB->DataCount = cpu_to_le16(count);
5174 pSMB->ParameterCount = cpu_to_le16(params);
5175 pSMB->TotalDataCount = pSMB->DataCount;
5176 pSMB->TotalParameterCount = pSMB->ParameterCount;
5177 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5178 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5179 else
5180 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5181 pSMB->Reserved4 = 0;
5182 pSMB->hdr.smb_buf_length += byte_count;
Steve French26f57362007-08-30 22:09:15 +00005183 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005184 pSMB->ByteCount = cpu_to_le16(byte_count);
5185 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5186 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005187 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005188 cFYI(1, "SetPathInfo (times) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005189
5190 cifs_buf_release(pSMB);
5191
5192 if (rc == -EAGAIN)
5193 goto SetTimesRetry;
5194
5195 return rc;
5196}
5197
5198/* Can not be used to set time stamps yet (due to old DOS time format) */
5199/* Can be used to set attributes */
5200#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5201 handling it anyway and NT4 was what we thought it would be needed for
5202 Do not delete it until we prove whether needed for Win9x though */
5203int
5204CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
5205 __u16 dos_attrs, const struct nls_table *nls_codepage)
5206{
5207 SETATTR_REQ *pSMB = NULL;
5208 SETATTR_RSP *pSMBr = NULL;
5209 int rc = 0;
5210 int bytes_returned;
5211 int name_len;
5212
Joe Perchesb6b38f72010-04-21 03:50:45 +00005213 cFYI(1, "In SetAttrLegacy");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005214
5215SetAttrLgcyRetry:
5216 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5217 (void **) &pSMBr);
5218 if (rc)
5219 return rc;
5220
5221 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5222 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005223 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005224 PATH_MAX, nls_codepage);
5225 name_len++; /* trailing null */
5226 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005227 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005228 name_len = strnlen(fileName, PATH_MAX);
5229 name_len++; /* trailing null */
5230 strncpy(pSMB->fileName, fileName, name_len);
5231 }
5232 pSMB->attr = cpu_to_le16(dos_attrs);
5233 pSMB->BufferFormat = 0x04;
5234 pSMB->hdr.smb_buf_length += name_len + 1;
5235 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5236 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5237 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005238 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005239 cFYI(1, "Error in LegacySetAttr = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005240
5241 cifs_buf_release(pSMB);
5242
5243 if (rc == -EAGAIN)
5244 goto SetAttrLgcyRetry;
5245
5246 return rc;
5247}
5248#endif /* temporarily unneeded SetAttr legacy function */
5249
Jeff Layton654cf142009-07-09 20:02:49 -04005250static void
5251cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5252 const struct cifs_unix_set_info_args *args)
5253{
5254 u64 mode = args->mode;
5255
5256 /*
5257 * Samba server ignores set of file size to zero due to bugs in some
5258 * older clients, but we should be precise - we use SetFileSize to
5259 * set file size and do not want to truncate file size to zero
5260 * accidently as happened on one Samba server beta by putting
5261 * zero instead of -1 here
5262 */
5263 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5264 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5265 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5266 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5267 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5268 data_offset->Uid = cpu_to_le64(args->uid);
5269 data_offset->Gid = cpu_to_le64(args->gid);
5270 /* better to leave device as zero when it is */
5271 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5272 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5273 data_offset->Permissions = cpu_to_le64(mode);
5274
5275 if (S_ISREG(mode))
5276 data_offset->Type = cpu_to_le32(UNIX_FILE);
5277 else if (S_ISDIR(mode))
5278 data_offset->Type = cpu_to_le32(UNIX_DIR);
5279 else if (S_ISLNK(mode))
5280 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5281 else if (S_ISCHR(mode))
5282 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5283 else if (S_ISBLK(mode))
5284 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5285 else if (S_ISFIFO(mode))
5286 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5287 else if (S_ISSOCK(mode))
5288 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5289}
5290
Linus Torvalds1da177e2005-04-16 15:20:36 -07005291int
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005292CIFSSMBUnixSetFileInfo(const int xid, struct cifsTconInfo *tcon,
5293 const struct cifs_unix_set_info_args *args,
5294 u16 fid, u32 pid_of_opener)
5295{
5296 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5297 FILE_UNIX_BASIC_INFO *data_offset;
5298 int rc = 0;
5299 u16 params, param_offset, offset, byte_count, count;
5300
Joe Perchesb6b38f72010-04-21 03:50:45 +00005301 cFYI(1, "Set Unix Info (via SetFileInfo)");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005302 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5303
5304 if (rc)
5305 return rc;
5306
5307 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5308 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5309
5310 params = 6;
5311 pSMB->MaxSetupCount = 0;
5312 pSMB->Reserved = 0;
5313 pSMB->Flags = 0;
5314 pSMB->Timeout = 0;
5315 pSMB->Reserved2 = 0;
5316 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5317 offset = param_offset + params;
5318
5319 data_offset = (FILE_UNIX_BASIC_INFO *)
5320 ((char *)(&pSMB->hdr.Protocol) + offset);
5321 count = sizeof(FILE_UNIX_BASIC_INFO);
5322
5323 pSMB->MaxParameterCount = cpu_to_le16(2);
5324 /* BB find max SMB PDU from sess */
5325 pSMB->MaxDataCount = cpu_to_le16(1000);
5326 pSMB->SetupCount = 1;
5327 pSMB->Reserved3 = 0;
5328 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5329 byte_count = 3 /* pad */ + params + count;
5330 pSMB->DataCount = cpu_to_le16(count);
5331 pSMB->ParameterCount = cpu_to_le16(params);
5332 pSMB->TotalDataCount = pSMB->DataCount;
5333 pSMB->TotalParameterCount = pSMB->ParameterCount;
5334 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5335 pSMB->DataOffset = cpu_to_le16(offset);
5336 pSMB->Fid = fid;
5337 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5338 pSMB->Reserved4 = 0;
5339 pSMB->hdr.smb_buf_length += byte_count;
5340 pSMB->ByteCount = cpu_to_le16(byte_count);
5341
5342 cifs_fill_unix_set_info(data_offset, args);
5343
5344 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
5345 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005346 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005347
5348 /* Note: On -EAGAIN error only caller can retry on handle based calls
5349 since file handle passed in no longer valid */
5350
5351 return rc;
5352}
5353
5354int
Jeff Layton01ea95e2009-07-09 20:02:49 -04005355CIFSSMBUnixSetPathInfo(const int xid, struct cifsTconInfo *tcon, char *fileName,
5356 const struct cifs_unix_set_info_args *args,
5357 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005358{
5359 TRANSACTION2_SPI_REQ *pSMB = NULL;
5360 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5361 int name_len;
5362 int rc = 0;
5363 int bytes_returned = 0;
5364 FILE_UNIX_BASIC_INFO *data_offset;
5365 __u16 params, param_offset, offset, count, byte_count;
5366
Joe Perchesb6b38f72010-04-21 03:50:45 +00005367 cFYI(1, "In SetUID/GID/Mode");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005368setPermsRetry:
5369 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5370 (void **) &pSMBr);
5371 if (rc)
5372 return rc;
5373
5374 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5375 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005376 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005377 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005378 name_len++; /* trailing null */
5379 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005380 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005381 name_len = strnlen(fileName, PATH_MAX);
5382 name_len++; /* trailing null */
5383 strncpy(pSMB->FileName, fileName, name_len);
5384 }
5385
5386 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005387 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005388 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005389 /* BB find max SMB PDU from sess structure BB */
5390 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005391 pSMB->MaxSetupCount = 0;
5392 pSMB->Reserved = 0;
5393 pSMB->Flags = 0;
5394 pSMB->Timeout = 0;
5395 pSMB->Reserved2 = 0;
5396 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005397 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005398 offset = param_offset + params;
5399 data_offset =
5400 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5401 offset);
5402 memset(data_offset, 0, count);
5403 pSMB->DataOffset = cpu_to_le16(offset);
5404 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5405 pSMB->SetupCount = 1;
5406 pSMB->Reserved3 = 0;
5407 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5408 byte_count = 3 /* pad */ + params + count;
5409 pSMB->ParameterCount = cpu_to_le16(params);
5410 pSMB->DataCount = cpu_to_le16(count);
5411 pSMB->TotalParameterCount = pSMB->ParameterCount;
5412 pSMB->TotalDataCount = pSMB->DataCount;
5413 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5414 pSMB->Reserved4 = 0;
5415 pSMB->hdr.smb_buf_length += byte_count;
Steve French50c2f752007-07-13 00:33:32 +00005416
Jeff Layton654cf142009-07-09 20:02:49 -04005417 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005418
5419 pSMB->ByteCount = cpu_to_le16(byte_count);
5420 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5421 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005422 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005423 cFYI(1, "SetPathInfo (perms) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005424
Steve French0d817bc2008-05-22 02:02:03 +00005425 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005426 if (rc == -EAGAIN)
5427 goto setPermsRetry;
5428 return rc;
5429}
5430
Steve French50c2f752007-07-13 00:33:32 +00005431int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07005432 const int notify_subdirs, const __u16 netfid,
Steve French50c2f752007-07-13 00:33:32 +00005433 __u32 filter, struct file *pfile, int multishot,
Steve French167a2512005-08-24 20:03:11 -07005434 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005435{
5436 int rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00005437 struct smb_com_transaction_change_notify_req *pSMB = NULL;
5438 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07005439 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005440 int bytes_returned;
5441
Joe Perchesb6b38f72010-04-21 03:50:45 +00005442 cFYI(1, "In CIFSSMBNotify for file handle %d", (int)netfid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005443 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00005444 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005445 if (rc)
5446 return rc;
5447
5448 pSMB->TotalParameterCount = 0 ;
5449 pSMB->TotalDataCount = 0;
5450 pSMB->MaxParameterCount = cpu_to_le32(2);
5451 /* BB find exact data count max from sess structure BB */
5452 pSMB->MaxDataCount = 0; /* same in little endian or be */
Steve French0a4b92c2006-01-12 15:44:21 -08005453/* BB VERIFY verify which is correct for above BB */
5454 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
5455 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
5456
Linus Torvalds1da177e2005-04-16 15:20:36 -07005457 pSMB->MaxSetupCount = 4;
5458 pSMB->Reserved = 0;
5459 pSMB->ParameterOffset = 0;
5460 pSMB->DataCount = 0;
5461 pSMB->DataOffset = 0;
5462 pSMB->SetupCount = 4; /* single byte does not need le conversion */
5463 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
5464 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00005465 if (notify_subdirs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005466 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
5467 pSMB->Reserved2 = 0;
5468 pSMB->CompletionFilter = cpu_to_le32(filter);
5469 pSMB->Fid = netfid; /* file handle always le */
5470 pSMB->ByteCount = 0;
5471
5472 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00005473 (struct smb_hdr *)pSMBr, &bytes_returned,
5474 CIFS_ASYNC_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005475 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005476 cFYI(1, "Error in Notify = %d", rc);
Steve Frenchff5dbd92005-08-24 17:10:36 -07005477 } else {
5478 /* Add file to outstanding requests */
Steve French50c2f752007-07-13 00:33:32 +00005479 /* BB change to kmem cache alloc */
Robert P. J. Day5cbded52006-12-13 00:35:56 -08005480 dnotify_req = kmalloc(
Steve French47c786e2005-10-11 20:03:18 -07005481 sizeof(struct dir_notify_req),
5482 GFP_KERNEL);
Steve French790fe572007-07-07 19:25:05 +00005483 if (dnotify_req) {
Steve French47c786e2005-10-11 20:03:18 -07005484 dnotify_req->Pid = pSMB->hdr.Pid;
5485 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
5486 dnotify_req->Mid = pSMB->hdr.Mid;
5487 dnotify_req->Tid = pSMB->hdr.Tid;
5488 dnotify_req->Uid = pSMB->hdr.Uid;
5489 dnotify_req->netfid = netfid;
5490 dnotify_req->pfile = pfile;
5491 dnotify_req->filter = filter;
5492 dnotify_req->multishot = multishot;
5493 spin_lock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005494 list_add_tail(&dnotify_req->lhead,
Steve French47c786e2005-10-11 20:03:18 -07005495 &GlobalDnotifyReqList);
5496 spin_unlock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005497 } else
Steve French47c786e2005-10-11 20:03:18 -07005498 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005499 }
5500 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00005501 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005502}
Jeff Layton31c05192010-02-10 16:18:26 -05005503
Linus Torvalds1da177e2005-04-16 15:20:36 -07005504#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05005505/*
5506 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
5507 * function used by listxattr and getxattr type calls. When ea_name is set,
5508 * it looks for that attribute name and stuffs that value into the EAData
5509 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
5510 * buffer. In both cases, the return value is either the length of the
5511 * resulting data or a negative error code. If EAData is a NULL pointer then
5512 * the data isn't copied to it, but the length is returned.
5513 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005514ssize_t
5515CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05005516 const unsigned char *searchName, const unsigned char *ea_name,
5517 char *EAData, size_t buf_size,
5518 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005519{
5520 /* BB assumes one setup word */
5521 TRANSACTION2_QPI_REQ *pSMB = NULL;
5522 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5523 int rc = 0;
5524 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05005525 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005526 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00005527 struct fea *temp_fea;
5528 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05005529 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005530 __u16 params, byte_count, data_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005531
Joe Perchesb6b38f72010-04-21 03:50:45 +00005532 cFYI(1, "In Query All EAs path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005533QAllEAsRetry:
5534 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5535 (void **) &pSMBr);
5536 if (rc)
5537 return rc;
5538
5539 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05005540 list_len =
Steve French50c2f752007-07-13 00:33:32 +00005541 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005542 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05005543 list_len++; /* trailing null */
5544 list_len *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005545 } else { /* BB improve the check for buffer overruns BB */
Jeff Layton6e462b92010-02-10 16:18:26 -05005546 list_len = strnlen(searchName, PATH_MAX);
5547 list_len++; /* trailing null */
5548 strncpy(pSMB->FileName, searchName, list_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005549 }
5550
Jeff Layton6e462b92010-02-10 16:18:26 -05005551 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005552 pSMB->TotalDataCount = 0;
5553 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005554 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05005555 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005556 pSMB->MaxSetupCount = 0;
5557 pSMB->Reserved = 0;
5558 pSMB->Flags = 0;
5559 pSMB->Timeout = 0;
5560 pSMB->Reserved2 = 0;
5561 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005562 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005563 pSMB->DataCount = 0;
5564 pSMB->DataOffset = 0;
5565 pSMB->SetupCount = 1;
5566 pSMB->Reserved3 = 0;
5567 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5568 byte_count = params + 1 /* pad */ ;
5569 pSMB->TotalParameterCount = cpu_to_le16(params);
5570 pSMB->ParameterCount = pSMB->TotalParameterCount;
5571 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5572 pSMB->Reserved4 = 0;
5573 pSMB->hdr.smb_buf_length += byte_count;
5574 pSMB->ByteCount = cpu_to_le16(byte_count);
5575
5576 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5577 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5578 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005579 cFYI(1, "Send error in QueryAllEAs = %d", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05005580 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005581 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05005582
5583
5584 /* BB also check enough total bytes returned */
5585 /* BB we need to improve the validity checking
5586 of these trans2 responses */
5587
5588 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5589 if (rc || (pSMBr->ByteCount < 4)) {
5590 rc = -EIO; /* bad smb */
5591 goto QAllEAsOut;
5592 }
5593
5594 /* check that length of list is not more than bcc */
5595 /* check that each entry does not go beyond length
5596 of list */
5597 /* check that each element of each entry does not
5598 go beyond end of list */
5599 /* validate_trans2_offsets() */
5600 /* BB check if start of smb + data_offset > &bcc+ bcc */
5601
5602 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5603 ea_response_data = (struct fealist *)
5604 (((char *) &pSMBr->hdr.Protocol) + data_offset);
5605
Jeff Layton6e462b92010-02-10 16:18:26 -05005606 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesb6b38f72010-04-21 03:50:45 +00005607 cFYI(1, "ea length %d", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05005608 if (list_len <= 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005609 cFYI(1, "empty EA list returned from server");
Jeff Laytonf0d38682010-02-10 16:18:26 -05005610 goto QAllEAsOut;
5611 }
5612
Jeff Layton0cd126b2010-02-10 16:18:26 -05005613 /* make sure list_len doesn't go past end of SMB */
5614 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + BCC(&pSMBr->hdr);
5615 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005616 cFYI(1, "EA list appears to go beyond SMB");
Jeff Layton0cd126b2010-02-10 16:18:26 -05005617 rc = -EIO;
5618 goto QAllEAsOut;
5619 }
5620
Jeff Laytonf0d38682010-02-10 16:18:26 -05005621 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05005622 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005623 temp_fea = ea_response_data->list;
5624 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05005625 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00005626 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005627 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05005628
Jeff Layton6e462b92010-02-10 16:18:26 -05005629 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005630 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05005631 /* make sure we can read name_len and value_len */
5632 if (list_len < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005633 cFYI(1, "EA entry goes beyond length of list");
Jeff Layton0cd126b2010-02-10 16:18:26 -05005634 rc = -EIO;
5635 goto QAllEAsOut;
5636 }
5637
5638 name_len = temp_fea->name_len;
5639 value_len = le16_to_cpu(temp_fea->value_len);
5640 list_len -= name_len + 1 + value_len;
5641 if (list_len < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005642 cFYI(1, "EA entry goes beyond length of list");
Jeff Layton0cd126b2010-02-10 16:18:26 -05005643 rc = -EIO;
5644 goto QAllEAsOut;
5645 }
5646
Jeff Layton31c05192010-02-10 16:18:26 -05005647 if (ea_name) {
5648 if (strncmp(ea_name, temp_ptr, name_len) == 0) {
5649 temp_ptr += name_len + 1;
5650 rc = value_len;
5651 if (buf_size == 0)
5652 goto QAllEAsOut;
5653 if ((size_t)value_len > buf_size) {
5654 rc = -ERANGE;
5655 goto QAllEAsOut;
5656 }
5657 memcpy(EAData, temp_ptr, value_len);
5658 goto QAllEAsOut;
5659 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05005660 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05005661 /* account for prefix user. and trailing null */
5662 rc += (5 + 1 + name_len);
5663 if (rc < (int) buf_size) {
5664 memcpy(EAData, "user.", 5);
5665 EAData += 5;
5666 memcpy(EAData, temp_ptr, name_len);
5667 EAData += name_len;
5668 /* null terminate name */
5669 *EAData = 0;
5670 ++EAData;
5671 } else if (buf_size == 0) {
5672 /* skip copy - calc size only */
5673 } else {
5674 /* stop before overrun buffer */
5675 rc = -ERANGE;
5676 break;
5677 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05005678 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05005679 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005680 temp_fea = (struct fea *)temp_ptr;
5681 }
5682
Jeff Layton31c05192010-02-10 16:18:26 -05005683 /* didn't find the named attribute */
5684 if (ea_name)
5685 rc = -ENODATA;
5686
Jeff Laytonf0d38682010-02-10 16:18:26 -05005687QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00005688 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005689 if (rc == -EAGAIN)
5690 goto QAllEAsRetry;
5691
5692 return (ssize_t)rc;
5693}
5694
Linus Torvalds1da177e2005-04-16 15:20:36 -07005695int
5696CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00005697 const char *ea_name, const void *ea_value,
5698 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5699 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005700{
5701 struct smb_com_transaction2_spi_req *pSMB = NULL;
5702 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5703 struct fealist *parm_data;
5704 int name_len;
5705 int rc = 0;
5706 int bytes_returned = 0;
5707 __u16 params, param_offset, byte_count, offset, count;
5708
Joe Perchesb6b38f72010-04-21 03:50:45 +00005709 cFYI(1, "In SetEA");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005710SetEARetry:
5711 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5712 (void **) &pSMBr);
5713 if (rc)
5714 return rc;
5715
5716 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5717 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005718 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005719 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005720 name_len++; /* trailing null */
5721 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005722 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005723 name_len = strnlen(fileName, PATH_MAX);
5724 name_len++; /* trailing null */
5725 strncpy(pSMB->FileName, fileName, name_len);
5726 }
5727
5728 params = 6 + name_len;
5729
5730 /* done calculating parms using name_len of file name,
5731 now use name_len to calculate length of ea name
5732 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00005733 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005734 name_len = 0;
5735 else
Steve French50c2f752007-07-13 00:33:32 +00005736 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005737
Steve Frenchdae5dbd2007-12-30 23:49:57 +00005738 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005739 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005740 /* BB find max SMB PDU from sess */
5741 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005742 pSMB->MaxSetupCount = 0;
5743 pSMB->Reserved = 0;
5744 pSMB->Flags = 0;
5745 pSMB->Timeout = 0;
5746 pSMB->Reserved2 = 0;
5747 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005748 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005749 offset = param_offset + params;
5750 pSMB->InformationLevel =
5751 cpu_to_le16(SMB_SET_FILE_EA);
5752
5753 parm_data =
5754 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5755 offset);
5756 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5757 pSMB->DataOffset = cpu_to_le16(offset);
5758 pSMB->SetupCount = 1;
5759 pSMB->Reserved3 = 0;
5760 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5761 byte_count = 3 /* pad */ + params + count;
5762 pSMB->DataCount = cpu_to_le16(count);
5763 parm_data->list_len = cpu_to_le32(count);
5764 parm_data->list[0].EA_flags = 0;
5765 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08005766 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005767 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00005768 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00005769 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005770 parm_data->list[0].name[name_len] = 0;
5771 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5772 /* caller ensures that ea_value_len is less than 64K but
5773 we need to ensure that it fits within the smb */
5774
Steve French50c2f752007-07-13 00:33:32 +00005775 /*BB add length check to see if it would fit in
5776 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00005777 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5778 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00005779 memcpy(parm_data->list[0].name+name_len+1,
5780 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005781
5782 pSMB->TotalDataCount = pSMB->DataCount;
5783 pSMB->ParameterCount = cpu_to_le16(params);
5784 pSMB->TotalParameterCount = pSMB->ParameterCount;
5785 pSMB->Reserved4 = 0;
5786 pSMB->hdr.smb_buf_length += byte_count;
5787 pSMB->ByteCount = cpu_to_le16(byte_count);
5788 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5789 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005790 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005791 cFYI(1, "SetPathInfo (EA) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005792
5793 cifs_buf_release(pSMB);
5794
5795 if (rc == -EAGAIN)
5796 goto SetEARetry;
5797
5798 return rc;
5799}
5800
5801#endif