blob: 5b1f6637f1611bcc6834ee67d72671f92a3f92d4 [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 /* even though we do not use raw we might as well set this
456 accurately, in case we ever find a need for it */
Steve French790fe572007-07-07 19:25:05 +0000457 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
Steve Frencheca6acf2009-02-20 05:43:09 +0000458 server->max_rw = 0xFF00;
Steve French254e55e2006-06-04 05:53:15 +0000459 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
460 } else {
Steve Frencheca6acf2009-02-20 05:43:09 +0000461 server->max_rw = 0;/* do not need to use raw anyway */
Steve French254e55e2006-06-04 05:53:15 +0000462 server->capabilities = CAP_MPX_MODE;
463 }
Steve Frenchb815f1e52006-10-02 05:53:29 +0000464 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
Steve French1a70d652006-10-02 05:59:18 +0000465 if (tmp == -1) {
Steve French25ee4a92006-09-30 00:54:23 +0000466 /* OS/2 often does not set timezone therefore
467 * we must use server time to calc time zone.
Steve Frenchb815f1e52006-10-02 05:53:29 +0000468 * Could deviate slightly from the right zone.
469 * Smallest defined timezone difference is 15 minutes
470 * (i.e. Nepal). Rounding up/down is done to match
471 * this requirement.
Steve French25ee4a92006-09-30 00:54:23 +0000472 */
Steve Frenchb815f1e52006-10-02 05:53:29 +0000473 int val, seconds, remain, result;
Steve French25ee4a92006-09-30 00:54:23 +0000474 struct timespec ts, utc;
475 utc = CURRENT_TIME;
Jeff Laytonc4a2c082009-05-27 09:37:33 -0400476 ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
477 rsp->SrvTime.Time, 0);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000478 cFYI(1, "SrvTime %d sec since 1970 (utc: %d) diff: %d",
Steve French50c2f752007-07-13 00:33:32 +0000479 (int)ts.tv_sec, (int)utc.tv_sec,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000480 (int)(utc.tv_sec - ts.tv_sec));
Steve Frenchb815f1e52006-10-02 05:53:29 +0000481 val = (int)(utc.tv_sec - ts.tv_sec);
Andre Haupt8594c152007-08-30 20:18:41 +0000482 seconds = abs(val);
Steve French947a5062006-10-02 05:55:25 +0000483 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
Steve Frenchb815f1e52006-10-02 05:53:29 +0000484 remain = seconds % MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000485 if (remain >= (MIN_TZ_ADJ / 2))
Steve Frenchb815f1e52006-10-02 05:53:29 +0000486 result += MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000487 if (val < 0)
Steve Frenchad7a2922008-02-07 23:25:02 +0000488 result = -result;
Steve Frenchb815f1e52006-10-02 05:53:29 +0000489 server->timeAdj = result;
Steve French25ee4a92006-09-30 00:54:23 +0000490 } else {
Steve Frenchb815f1e52006-10-02 05:53:29 +0000491 server->timeAdj = (int)tmp;
492 server->timeAdj *= 60; /* also in seconds */
Steve French25ee4a92006-09-30 00:54:23 +0000493 }
Joe Perchesb6b38f72010-04-21 03:50:45 +0000494 cFYI(1, "server->timeAdj: %d seconds", server->timeAdj);
Steve French25ee4a92006-09-30 00:54:23 +0000495
Steve French39798772006-05-31 22:40:51 +0000496
Steve French254e55e2006-06-04 05:53:15 +0000497 /* BB get server time for time conversions and add
Steve French50c2f752007-07-13 00:33:32 +0000498 code to use it and timezone since this is not UTC */
Steve French39798772006-05-31 22:40:51 +0000499
Steve French50c2f752007-07-13 00:33:32 +0000500 if (rsp->EncryptionKeyLength ==
Steve French25ee4a92006-09-30 00:54:23 +0000501 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500502 memcpy(ses->server->cryptkey, rsp->EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000503 CIFS_CRYPTO_KEY_SIZE);
504 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
505 rc = -EIO; /* need cryptkey unless plain text */
506 goto neg_err_exit;
507 }
Steve French39798772006-05-31 22:40:51 +0000508
Steve Frenchf19159d2010-04-21 04:12:10 +0000509 cFYI(1, "LANMAN negotiated");
Steve French254e55e2006-06-04 05:53:15 +0000510 /* we will not end up setting signing flags - as no signing
511 was in LANMAN and server did not return the flags on */
512 goto signing_check;
Steve French7c7b25b2006-06-01 19:20:10 +0000513#else /* weak security disabled */
Steve French790fe572007-07-07 19:25:05 +0000514 } else if (pSMBr->hdr.WordCount == 13) {
Steve Frenchf19159d2010-04-21 04:12:10 +0000515 cERROR(1, "mount failed, cifs module not built "
516 "with CIFS_WEAK_PW_HASH support");
Dan Carpenter8212cf72010-03-15 11:22:26 +0300517 rc = -EOPNOTSUPP;
Steve French7c7b25b2006-06-01 19:20:10 +0000518#endif /* WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000519 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000520 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000521 /* unknown wct */
522 rc = -EOPNOTSUPP;
523 goto neg_err_exit;
524 }
525 /* else wct == 17 NTLM */
526 server->secMode = pSMBr->SecurityMode;
Steve French790fe572007-07-07 19:25:05 +0000527 if ((server->secMode & SECMODE_USER) == 0)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000528 cFYI(1, "share mode security");
Steve French39798772006-05-31 22:40:51 +0000529
Steve French790fe572007-07-07 19:25:05 +0000530 if ((server->secMode & SECMODE_PW_ENCRYPT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000531#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French750d1152006-06-27 06:28:30 +0000532 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000533#endif /* CIFS_WEAK_PW_HASH */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000534 cERROR(1, "Server requests plain text password"
535 " but client support disabled");
Steve French9312f672006-06-04 22:21:07 +0000536
Steve French790fe572007-07-07 19:25:05 +0000537 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
Steve French254e55e2006-06-04 05:53:15 +0000538 server->secType = NTLMv2;
Steve French790fe572007-07-07 19:25:05 +0000539 else if (secFlags & CIFSSEC_MAY_NTLM)
Steve French254e55e2006-06-04 05:53:15 +0000540 server->secType = NTLM;
Steve French790fe572007-07-07 19:25:05 +0000541 else if (secFlags & CIFSSEC_MAY_NTLMV2)
Steve Frenchf40c5622006-06-28 00:13:38 +0000542 server->secType = NTLMv2;
Steve Frencha0136892007-10-04 20:05:09 +0000543 else if (secFlags & CIFSSEC_MAY_KRB5)
544 server->secType = Kerberos;
Steve Frenchac683922009-05-06 04:16:04 +0000545 else if (secFlags & CIFSSEC_MAY_NTLMSSP)
Steve Frenchf46c7232009-06-25 03:04:20 +0000546 server->secType = RawNTLMSSP;
Steve Frencha0136892007-10-04 20:05:09 +0000547 else if (secFlags & CIFSSEC_MAY_LANMAN)
548 server->secType = LANMAN;
549/* #ifdef CONFIG_CIFS_EXPERIMENTAL
550 else if (secFlags & CIFSSEC_MAY_PLNTXT)
551 server->secType = ??
552#endif */
553 else {
554 rc = -EOPNOTSUPP;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000555 cERROR(1, "Invalid security type");
Steve Frencha0136892007-10-04 20:05:09 +0000556 goto neg_err_exit;
557 }
558 /* else ... any others ...? */
Steve French7c7b25b2006-06-01 19:20:10 +0000559
Steve French254e55e2006-06-04 05:53:15 +0000560 /* one byte, so no need to convert this or EncryptionKeyLen from
561 little endian */
562 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
563 /* probably no need to store and check maxvcs */
564 server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve Frencheca6acf2009-02-20 05:43:09 +0000566 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000567 cFYI(DBG2, "Max buf = %d", ses->server->maxBuf);
Steve French254e55e2006-06-04 05:53:15 +0000568 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e52006-10-02 05:53:29 +0000569 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
570 server->timeAdj *= 60;
Steve French254e55e2006-06-04 05:53:15 +0000571 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500572 memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000573 CIFS_CRYPTO_KEY_SIZE);
574 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
575 && (pSMBr->EncryptionKeyLength == 0)) {
576 /* decode security blob */
577 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
578 rc = -EIO; /* no crypt key only if plain text pwd */
579 goto neg_err_exit;
580 }
581
582 /* BB might be helpful to save off the domain of server here */
583
Steve French50c2f752007-07-13 00:33:32 +0000584 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
Steve French254e55e2006-06-04 05:53:15 +0000585 (server->capabilities & CAP_EXTENDED_SECURITY)) {
586 count = pSMBr->ByteCount;
Jeff Laytone187e442007-10-16 17:10:44 +0000587 if (count < 16) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588 rc = -EIO;
Jeff Laytone187e442007-10-16 17:10:44 +0000589 goto neg_err_exit;
590 }
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530591 spin_lock(&cifs_tcp_ses_lock);
Jeff Laytone7ddee92008-11-14 13:44:38 -0500592 if (server->srv_count > 1) {
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530593 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000594 if (memcmp(server->server_GUID,
595 pSMBr->u.extended_response.
596 GUID, 16) != 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000597 cFYI(1, "server UID changed");
Steve French254e55e2006-06-04 05:53:15 +0000598 memcpy(server->server_GUID,
Jeff Laytone187e442007-10-16 17:10:44 +0000599 pSMBr->u.extended_response.GUID,
600 16);
601 }
Jeff Laytone7ddee92008-11-14 13:44:38 -0500602 } else {
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530603 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000604 memcpy(server->server_GUID,
605 pSMBr->u.extended_response.GUID, 16);
Jeff Laytone7ddee92008-11-14 13:44:38 -0500606 }
Jeff Laytone187e442007-10-16 17:10:44 +0000607
608 if (count == 16) {
609 server->secType = RawNTLMSSP;
Steve French254e55e2006-06-04 05:53:15 +0000610 } else {
611 rc = decode_negTokenInit(pSMBr->u.extended_response.
Jeff Layton26efa0b2010-04-24 07:57:49 -0400612 SecurityBlob, count - 16,
613 server);
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000614 if (rc == 1)
Jeff Laytone5459372007-11-03 05:11:06 +0000615 rc = 0;
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000616 else
Steve French254e55e2006-06-04 05:53:15 +0000617 rc = -EINVAL;
Shirish Pargaonkar2b149f12010-09-18 22:02:18 -0500618 if (server->secType == Kerberos) {
619 if (!server->sec_kerberos &&
620 !server->sec_mskerberos)
621 rc = -EOPNOTSUPP;
622 } else if (server->secType == RawNTLMSSP) {
623 if (!server->sec_ntlmssp)
624 rc = -EOPNOTSUPP;
625 } else
626 rc = -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 }
Steve French254e55e2006-06-04 05:53:15 +0000628 } else
629 server->capabilities &= ~CAP_EXTENDED_SECURITY;
630
Steve French6344a422006-06-12 04:18:35 +0000631#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French254e55e2006-06-04 05:53:15 +0000632signing_check:
Steve French6344a422006-06-12 04:18:35 +0000633#endif
Steve French762e5ab2007-06-28 18:41:42 +0000634 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
635 /* MUST_SIGN already includes the MAY_SIGN FLAG
636 so if this is zero it means that signing is disabled */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000637 cFYI(1, "Signing disabled");
Steve Frenchabb63d62007-10-18 02:58:40 +0000638 if (server->secMode & SECMODE_SIGN_REQUIRED) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000639 cERROR(1, "Server requires "
Jeff Layton7111d212007-10-16 16:50:25 +0000640 "packet signing to be enabled in "
Joe Perchesb6b38f72010-04-21 03:50:45 +0000641 "/proc/fs/cifs/SecurityFlags.");
Steve Frenchabb63d62007-10-18 02:58:40 +0000642 rc = -EOPNOTSUPP;
643 }
Steve French50c2f752007-07-13 00:33:32 +0000644 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000645 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Steve French762e5ab2007-06-28 18:41:42 +0000646 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
647 /* signing required */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000648 cFYI(1, "Must sign - secFlags 0x%x", secFlags);
Steve French762e5ab2007-06-28 18:41:42 +0000649 if ((server->secMode &
650 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000651 cERROR(1, "signing required but server lacks support");
Jeff38c10a12007-07-06 21:10:07 +0000652 rc = -EOPNOTSUPP;
Steve French762e5ab2007-06-28 18:41:42 +0000653 } else
654 server->secMode |= SECMODE_SIGN_REQUIRED;
655 } else {
656 /* signing optional ie CIFSSEC_MAY_SIGN */
Steve French790fe572007-07-07 19:25:05 +0000657 if ((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
Steve French50c2f752007-07-13 00:33:32 +0000658 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000659 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 }
Steve French50c2f752007-07-13 00:33:32 +0000661
662neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700663 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000664
Joe Perchesb6b38f72010-04-21 03:50:45 +0000665 cFYI(1, "negprot rc %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 return rc;
667}
668
669int
670CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
671{
672 struct smb_hdr *smb_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674
Joe Perchesb6b38f72010-04-21 03:50:45 +0000675 cFYI(1, "In tree disconnect");
Jeff Laytonf1987b42008-11-15 11:12:47 -0500676
677 /* BB: do we need to check this? These should never be NULL. */
678 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
679 return -EIO;
680
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 /*
Jeff Laytonf1987b42008-11-15 11:12:47 -0500682 * No need to return error on this operation if tid invalidated and
683 * closed on server already e.g. due to tcp session crashing. Also,
684 * the tcon is no longer on the list, so no need to take lock before
685 * checking this.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 */
Steve French268875b2009-06-25 00:29:21 +0000687 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
Steve French50c2f752007-07-13 00:33:32 +0000688 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689
Steve French50c2f752007-07-13 00:33:32 +0000690 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700691 (void **)&smb_buffer);
Jeff Laytonf1987b42008-11-15 11:12:47 -0500692 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 return rc;
Steve French133672e2007-11-13 22:41:37 +0000694
695 rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000697 cFYI(1, "Tree disconnect failed %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698
Steve French50c2f752007-07-13 00:33:32 +0000699 /* No need to return error on this operation if tid invalidated and
Jeff Laytonf1987b42008-11-15 11:12:47 -0500700 closed on server already e.g. due to tcp session crashing */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701 if (rc == -EAGAIN)
702 rc = 0;
703
704 return rc;
705}
706
Jeff Layton766fdbb2011-01-11 07:24:21 -0500707/*
708 * This is a no-op for now. We're not really interested in the reply, but
709 * rather in the fact that the server sent one and that server->lstrp
710 * gets updated.
711 *
712 * FIXME: maybe we should consider checking that the reply matches request?
713 */
714static void
715cifs_echo_callback(struct mid_q_entry *mid)
716{
717 struct TCP_Server_Info *server = mid->callback_data;
718
719 DeleteMidQEntry(mid);
720 atomic_dec(&server->inFlight);
721 wake_up(&server->request_q);
722}
723
724int
725CIFSSMBEcho(struct TCP_Server_Info *server)
726{
727 ECHO_REQ *smb;
728 int rc = 0;
729
730 cFYI(1, "In echo request");
731
732 rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
733 if (rc)
734 return rc;
735
736 /* set up echo request */
737 smb->hdr.Tid = cpu_to_le16(0xffff);
738 smb->hdr.WordCount = cpu_to_le16(1);
739 smb->EchoCount = cpu_to_le16(1);
740 smb->ByteCount = cpu_to_le16(1);
741 smb->Data[0] = 'a';
742 smb->hdr.smb_buf_length += 3;
743
744 rc = cifs_call_async(server, (struct smb_hdr *)smb,
745 cifs_echo_callback, server);
746 if (rc)
747 cFYI(1, "Echo request failed: %d", rc);
748
749 cifs_small_buf_release(smb);
750
751 return rc;
752}
753
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754int
755CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
756{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 LOGOFF_ANDX_REQ *pSMB;
758 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759
Joe Perchesb6b38f72010-04-21 03:50:45 +0000760 cFYI(1, "In SMBLogoff for session disconnect");
Jeff Layton14fbf502008-11-14 13:53:46 -0500761
762 /*
763 * BB: do we need to check validity of ses and server? They should
764 * always be valid since we have an active reference. If not, that
765 * should probably be a BUG()
766 */
767 if (!ses || !ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 return -EIO;
769
Steve Frenchd7b619c2010-02-25 05:36:46 +0000770 mutex_lock(&ses->session_mutex);
Steve French3b795212008-11-13 19:45:32 +0000771 if (ses->need_reconnect)
772 goto session_already_dead; /* no need to send SMBlogoff if uid
773 already closed due to reconnect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
775 if (rc) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000776 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 return rc;
778 }
779
Steve French3b795212008-11-13 19:45:32 +0000780 pSMB->hdr.Mid = GetNextMid(ses->server);
Steve French1982c342005-08-17 12:38:22 -0700781
Steve French3b795212008-11-13 19:45:32 +0000782 if (ses->server->secMode &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
784 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785
786 pSMB->hdr.Uid = ses->Suid;
787
788 pSMB->AndXCommand = 0xFF;
Steve French133672e2007-11-13 22:41:37 +0000789 rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
Steve French3b795212008-11-13 19:45:32 +0000790session_already_dead:
Steve Frenchd7b619c2010-02-25 05:36:46 +0000791 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792
793 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000794 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 error */
796 if (rc == -EAGAIN)
797 rc = 0;
798 return rc;
799}
800
801int
Steve French2d785a52007-07-15 01:48:57 +0000802CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
803 __u16 type, const struct nls_table *nls_codepage, int remap)
804{
805 TRANSACTION2_SPI_REQ *pSMB = NULL;
806 TRANSACTION2_SPI_RSP *pSMBr = NULL;
807 struct unlink_psx_rq *pRqD;
808 int name_len;
809 int rc = 0;
810 int bytes_returned = 0;
811 __u16 params, param_offset, offset, byte_count;
812
Joe Perchesb6b38f72010-04-21 03:50:45 +0000813 cFYI(1, "In POSIX delete");
Steve French2d785a52007-07-15 01:48:57 +0000814PsxDelete:
815 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
816 (void **) &pSMBr);
817 if (rc)
818 return rc;
819
820 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
821 name_len =
822 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
823 PATH_MAX, nls_codepage, remap);
824 name_len++; /* trailing null */
825 name_len *= 2;
826 } else { /* BB add path length overrun check */
827 name_len = strnlen(fileName, PATH_MAX);
828 name_len++; /* trailing null */
829 strncpy(pSMB->FileName, fileName, name_len);
830 }
831
832 params = 6 + name_len;
833 pSMB->MaxParameterCount = cpu_to_le16(2);
834 pSMB->MaxDataCount = 0; /* BB double check this with jra */
835 pSMB->MaxSetupCount = 0;
836 pSMB->Reserved = 0;
837 pSMB->Flags = 0;
838 pSMB->Timeout = 0;
839 pSMB->Reserved2 = 0;
840 param_offset = offsetof(struct smb_com_transaction2_spi_req,
841 InformationLevel) - 4;
842 offset = param_offset + params;
843
844 /* Setup pointer to Request Data (inode type) */
845 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
846 pRqD->type = cpu_to_le16(type);
847 pSMB->ParameterOffset = cpu_to_le16(param_offset);
848 pSMB->DataOffset = cpu_to_le16(offset);
849 pSMB->SetupCount = 1;
850 pSMB->Reserved3 = 0;
851 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
852 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
853
854 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
855 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
856 pSMB->ParameterCount = cpu_to_le16(params);
857 pSMB->TotalParameterCount = pSMB->ParameterCount;
858 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
859 pSMB->Reserved4 = 0;
860 pSMB->hdr.smb_buf_length += byte_count;
861 pSMB->ByteCount = cpu_to_le16(byte_count);
862 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
863 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000864 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000865 cFYI(1, "Posix delete returned %d", rc);
Steve French2d785a52007-07-15 01:48:57 +0000866 cifs_buf_release(pSMB);
867
868 cifs_stats_inc(&tcon->num_deletes);
869
870 if (rc == -EAGAIN)
871 goto PsxDelete;
872
873 return rc;
874}
875
876int
Steve French737b7582005-04-28 22:41:06 -0700877CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
878 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879{
880 DELETE_FILE_REQ *pSMB = NULL;
881 DELETE_FILE_RSP *pSMBr = NULL;
882 int rc = 0;
883 int bytes_returned;
884 int name_len;
885
886DelFileRetry:
887 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
888 (void **) &pSMBr);
889 if (rc)
890 return rc;
891
892 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
893 name_len =
Steve French50c2f752007-07-13 00:33:32 +0000894 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
Steve French737b7582005-04-28 22:41:06 -0700895 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 name_len++; /* trailing null */
897 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700898 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899 name_len = strnlen(fileName, PATH_MAX);
900 name_len++; /* trailing null */
901 strncpy(pSMB->fileName, fileName, name_len);
902 }
903 pSMB->SearchAttributes =
904 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
905 pSMB->BufferFormat = 0x04;
906 pSMB->hdr.smb_buf_length += name_len + 1;
907 pSMB->ByteCount = cpu_to_le16(name_len + 1);
908 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
909 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700910 cifs_stats_inc(&tcon->num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000911 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000912 cFYI(1, "Error in RMFile = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913
914 cifs_buf_release(pSMB);
915 if (rc == -EAGAIN)
916 goto DelFileRetry;
917
918 return rc;
919}
920
921int
Steve French50c2f752007-07-13 00:33:32 +0000922CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
Steve French737b7582005-04-28 22:41:06 -0700923 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924{
925 DELETE_DIRECTORY_REQ *pSMB = NULL;
926 DELETE_DIRECTORY_RSP *pSMBr = NULL;
927 int rc = 0;
928 int bytes_returned;
929 int name_len;
930
Joe Perchesb6b38f72010-04-21 03:50:45 +0000931 cFYI(1, "In CIFSSMBRmDir");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932RmDirRetry:
933 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
934 (void **) &pSMBr);
935 if (rc)
936 return rc;
937
938 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French737b7582005-04-28 22:41:06 -0700939 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
940 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941 name_len++; /* trailing null */
942 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700943 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944 name_len = strnlen(dirName, PATH_MAX);
945 name_len++; /* trailing null */
946 strncpy(pSMB->DirName, dirName, name_len);
947 }
948
949 pSMB->BufferFormat = 0x04;
950 pSMB->hdr.smb_buf_length += name_len + 1;
951 pSMB->ByteCount = cpu_to_le16(name_len + 1);
952 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
953 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700954 cifs_stats_inc(&tcon->num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000955 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000956 cFYI(1, "Error in RMDir = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957
958 cifs_buf_release(pSMB);
959 if (rc == -EAGAIN)
960 goto RmDirRetry;
961 return rc;
962}
963
964int
965CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -0700966 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967{
968 int rc = 0;
969 CREATE_DIRECTORY_REQ *pSMB = NULL;
970 CREATE_DIRECTORY_RSP *pSMBr = NULL;
971 int bytes_returned;
972 int name_len;
973
Joe Perchesb6b38f72010-04-21 03:50:45 +0000974 cFYI(1, "In CIFSSMBMkDir");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975MkDirRetry:
976 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
977 (void **) &pSMBr);
978 if (rc)
979 return rc;
980
981 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +0000982 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
Steve French737b7582005-04-28 22:41:06 -0700983 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 name_len++; /* trailing null */
985 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700986 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987 name_len = strnlen(name, PATH_MAX);
988 name_len++; /* trailing null */
989 strncpy(pSMB->DirName, name, name_len);
990 }
991
992 pSMB->BufferFormat = 0x04;
993 pSMB->hdr.smb_buf_length += name_len + 1;
994 pSMB->ByteCount = cpu_to_le16(name_len + 1);
995 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
996 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700997 cifs_stats_inc(&tcon->num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000998 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000999 cFYI(1, "Error in Mkdir = %d", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07001000
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001 cifs_buf_release(pSMB);
1002 if (rc == -EAGAIN)
1003 goto MkDirRetry;
1004 return rc;
1005}
1006
Steve French2dd29d32007-04-23 22:07:35 +00001007int
1008CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
Steve Frenchad7a2922008-02-07 23:25:02 +00001009 __u64 mode, __u16 *netfid, FILE_UNIX_BASIC_INFO *pRetData,
Steve French50c2f752007-07-13 00:33:32 +00001010 __u32 *pOplock, const char *name,
Steve French2dd29d32007-04-23 22:07:35 +00001011 const struct nls_table *nls_codepage, int remap)
1012{
1013 TRANSACTION2_SPI_REQ *pSMB = NULL;
1014 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1015 int name_len;
1016 int rc = 0;
1017 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001018 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +00001019 OPEN_PSX_REQ *pdata;
1020 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +00001021
Joe Perchesb6b38f72010-04-21 03:50:45 +00001022 cFYI(1, "In POSIX Create");
Steve French2dd29d32007-04-23 22:07:35 +00001023PsxCreat:
1024 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1025 (void **) &pSMBr);
1026 if (rc)
1027 return rc;
1028
1029 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1030 name_len =
1031 cifsConvertToUCS((__le16 *) pSMB->FileName, name,
1032 PATH_MAX, nls_codepage, remap);
1033 name_len++; /* trailing null */
1034 name_len *= 2;
1035 } else { /* BB improve the check for buffer overruns BB */
1036 name_len = strnlen(name, PATH_MAX);
1037 name_len++; /* trailing null */
1038 strncpy(pSMB->FileName, name, name_len);
1039 }
1040
1041 params = 6 + name_len;
1042 count = sizeof(OPEN_PSX_REQ);
1043 pSMB->MaxParameterCount = cpu_to_le16(2);
1044 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1045 pSMB->MaxSetupCount = 0;
1046 pSMB->Reserved = 0;
1047 pSMB->Flags = 0;
1048 pSMB->Timeout = 0;
1049 pSMB->Reserved2 = 0;
1050 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001051 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001052 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001053 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001054 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001055 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001056 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001057 pdata->OpenFlags = cpu_to_le32(*pOplock);
1058 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1059 pSMB->DataOffset = cpu_to_le16(offset);
1060 pSMB->SetupCount = 1;
1061 pSMB->Reserved3 = 0;
1062 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1063 byte_count = 3 /* pad */ + params + count;
1064
1065 pSMB->DataCount = cpu_to_le16(count);
1066 pSMB->ParameterCount = cpu_to_le16(params);
1067 pSMB->TotalDataCount = pSMB->DataCount;
1068 pSMB->TotalParameterCount = pSMB->ParameterCount;
1069 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1070 pSMB->Reserved4 = 0;
Steve French50c2f752007-07-13 00:33:32 +00001071 pSMB->hdr.smb_buf_length += byte_count;
Steve French2dd29d32007-04-23 22:07:35 +00001072 pSMB->ByteCount = cpu_to_le16(byte_count);
1073 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1074 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1075 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001076 cFYI(1, "Posix create returned %d", rc);
Steve French2dd29d32007-04-23 22:07:35 +00001077 goto psx_create_err;
1078 }
1079
Joe Perchesb6b38f72010-04-21 03:50:45 +00001080 cFYI(1, "copying inode info");
Steve French2dd29d32007-04-23 22:07:35 +00001081 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1082
1083 if (rc || (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP))) {
1084 rc = -EIO; /* bad smb */
1085 goto psx_create_err;
1086 }
1087
1088 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001089 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001090 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001091
Steve French2dd29d32007-04-23 22:07:35 +00001092 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001093 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001094 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1095 /* Let caller know file was created so we can set the mode. */
1096 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001097 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001098 *pOplock |= CIFS_CREATE_ACTION;
1099 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001100 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1101 pRetData->Type = cpu_to_le32(-1); /* unknown */
Joe Perchesb6b38f72010-04-21 03:50:45 +00001102 cFYI(DBG2, "unknown type");
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001103 } else {
Steve French790fe572007-07-07 19:25:05 +00001104 if (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001105 + sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001106 cERROR(1, "Open response data too small");
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001107 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001108 goto psx_create_err;
1109 }
Steve French50c2f752007-07-13 00:33:32 +00001110 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001111 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001112 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001113 }
Steve French2dd29d32007-04-23 22:07:35 +00001114
1115psx_create_err:
1116 cifs_buf_release(pSMB);
1117
Steve French65bc98b2009-07-10 15:27:25 +00001118 if (posix_flags & SMB_O_DIRECTORY)
1119 cifs_stats_inc(&tcon->num_posixmkdirs);
1120 else
1121 cifs_stats_inc(&tcon->num_posixopens);
Steve French2dd29d32007-04-23 22:07:35 +00001122
1123 if (rc == -EAGAIN)
1124 goto PsxCreat;
1125
Steve French50c2f752007-07-13 00:33:32 +00001126 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001127}
1128
Steve Frencha9d02ad2005-08-24 23:06:05 -07001129static __u16 convert_disposition(int disposition)
1130{
1131 __u16 ofun = 0;
1132
1133 switch (disposition) {
1134 case FILE_SUPERSEDE:
1135 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1136 break;
1137 case FILE_OPEN:
1138 ofun = SMBOPEN_OAPPEND;
1139 break;
1140 case FILE_CREATE:
1141 ofun = SMBOPEN_OCREATE;
1142 break;
1143 case FILE_OPEN_IF:
1144 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1145 break;
1146 case FILE_OVERWRITE:
1147 ofun = SMBOPEN_OTRUNC;
1148 break;
1149 case FILE_OVERWRITE_IF:
1150 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1151 break;
1152 default:
Joe Perchesb6b38f72010-04-21 03:50:45 +00001153 cFYI(1, "unknown disposition %d", disposition);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001154 ofun = SMBOPEN_OAPPEND; /* regular open */
1155 }
1156 return ofun;
1157}
1158
Jeff Layton35fc37d2008-05-14 10:22:03 -07001159static int
1160access_flags_to_smbopen_mode(const int access_flags)
1161{
1162 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1163
1164 if (masked_flags == GENERIC_READ)
1165 return SMBOPEN_READ;
1166 else if (masked_flags == GENERIC_WRITE)
1167 return SMBOPEN_WRITE;
1168
1169 /* just go for read/write */
1170 return SMBOPEN_READWRITE;
1171}
1172
Steve Frencha9d02ad2005-08-24 23:06:05 -07001173int
1174SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
1175 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001176 const int access_flags, const int create_options, __u16 *netfid,
1177 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001178 const struct nls_table *nls_codepage, int remap)
1179{
1180 int rc = -EACCES;
1181 OPENX_REQ *pSMB = NULL;
1182 OPENX_RSP *pSMBr = NULL;
1183 int bytes_returned;
1184 int name_len;
1185 __u16 count;
1186
1187OldOpenRetry:
1188 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1189 (void **) &pSMBr);
1190 if (rc)
1191 return rc;
1192
1193 pSMB->AndXCommand = 0xFF; /* none */
1194
1195 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1196 count = 1; /* account for one byte pad to word boundary */
1197 name_len =
1198 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1199 fileName, PATH_MAX, nls_codepage, remap);
1200 name_len++; /* trailing null */
1201 name_len *= 2;
1202 } else { /* BB improve check for buffer overruns BB */
1203 count = 0; /* no pad */
1204 name_len = strnlen(fileName, PATH_MAX);
1205 name_len++; /* trailing null */
1206 strncpy(pSMB->fileName, fileName, name_len);
1207 }
1208 if (*pOplock & REQ_OPLOCK)
1209 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001210 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001211 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001212
Steve Frencha9d02ad2005-08-24 23:06:05 -07001213 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001214 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001215 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1216 /* set file as system file if special file such
1217 as fifo and server expecting SFU style and
1218 no Unix extensions */
1219
Steve French790fe572007-07-07 19:25:05 +00001220 if (create_options & CREATE_OPTION_SPECIAL)
1221 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001222 else /* BB FIXME BB */
1223 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001224
Jeff Layton67750fb2008-05-09 22:28:02 +00001225 if (create_options & CREATE_OPTION_READONLY)
1226 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001227
1228 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001229/* pSMB->CreateOptions = cpu_to_le32(create_options &
1230 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001231 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001232
1233 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001234 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001235 count += name_len;
1236 pSMB->hdr.smb_buf_length += count;
1237
1238 pSMB->ByteCount = cpu_to_le16(count);
1239 /* long_op set to 1 to allow for oplock break timeouts */
1240 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001241 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001242 cifs_stats_inc(&tcon->num_opens);
1243 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001244 cFYI(1, "Error in Open = %d", rc);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001245 } else {
1246 /* BB verify if wct == 15 */
1247
Steve French582d21e2008-05-13 04:54:12 +00001248/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001249
1250 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1251 /* Let caller know file was created so we can set the mode. */
1252 /* Do we care about the CreateAction in any other cases? */
1253 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001254/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001255 *pOplock |= CIFS_CREATE_ACTION; */
1256 /* BB FIXME END */
1257
Steve French790fe572007-07-07 19:25:05 +00001258 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001259 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1260 pfile_info->LastAccessTime = 0; /* BB fixme */
1261 pfile_info->LastWriteTime = 0; /* BB fixme */
1262 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001263 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001264 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001265 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001266 pfile_info->AllocationSize =
1267 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1268 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001269 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001270 pfile_info->DeletePending = 0;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001271 }
1272 }
1273
1274 cifs_buf_release(pSMB);
1275 if (rc == -EAGAIN)
1276 goto OldOpenRetry;
1277 return rc;
1278}
1279
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280int
1281CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1282 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001283 const int access_flags, const int create_options, __u16 *netfid,
1284 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001285 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286{
1287 int rc = -EACCES;
1288 OPEN_REQ *pSMB = NULL;
1289 OPEN_RSP *pSMBr = NULL;
1290 int bytes_returned;
1291 int name_len;
1292 __u16 count;
1293
1294openRetry:
1295 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1296 (void **) &pSMBr);
1297 if (rc)
1298 return rc;
1299
1300 pSMB->AndXCommand = 0xFF; /* none */
1301
1302 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1303 count = 1; /* account for one byte pad to word boundary */
1304 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001305 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -07001306 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307 name_len++; /* trailing null */
1308 name_len *= 2;
1309 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001310 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311 count = 0; /* no pad */
1312 name_len = strnlen(fileName, PATH_MAX);
1313 name_len++; /* trailing null */
1314 pSMB->NameLength = cpu_to_le16(name_len);
1315 strncpy(pSMB->fileName, fileName, name_len);
1316 }
1317 if (*pOplock & REQ_OPLOCK)
1318 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001319 else if (*pOplock & REQ_BATCHOPLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1322 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -07001323 /* set file as system file if special file such
1324 as fifo and server expecting SFU style and
1325 no Unix extensions */
Steve French790fe572007-07-07 19:25:05 +00001326 if (create_options & CREATE_OPTION_SPECIAL)
Steve Frencheda3c0292005-07-21 15:20:28 -07001327 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1328 else
1329 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Jeff Layton67750fb2008-05-09 22:28:02 +00001330
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331 /* XP does not handle ATTR_POSIX_SEMANTICS */
1332 /* but it helps speed up case sensitive checks for other
1333 servers such as Samba */
1334 if (tcon->ses->capabilities & CAP_UNIX)
1335 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1336
Jeff Layton67750fb2008-05-09 22:28:02 +00001337 if (create_options & CREATE_OPTION_READONLY)
1338 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1339
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1341 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -07001342 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001343 /* BB Expirement with various impersonation levels and verify */
1344 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345 pSMB->SecurityFlags =
1346 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1347
1348 count += name_len;
1349 pSMB->hdr.smb_buf_length += count;
1350
1351 pSMB->ByteCount = cpu_to_le16(count);
1352 /* long_op set to 1 to allow for oplock break timeouts */
1353 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001354 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001355 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001357 cFYI(1, "Error in Open = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 } else {
Steve French09d1db52005-04-28 22:41:08 -07001359 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1361 /* Let caller know file was created so we can set the mode. */
1362 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001363 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve French50c2f752007-07-13 00:33:32 +00001364 *pOplock |= CIFS_CREATE_ACTION;
Steve French790fe572007-07-07 19:25:05 +00001365 if (pfile_info) {
Steve French61e74802008-12-03 00:57:54 +00001366 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1367 36 /* CreationTime to Attributes */);
1368 /* the file_info buf is endian converted by caller */
1369 pfile_info->AllocationSize = pSMBr->AllocationSize;
1370 pfile_info->EndOfFile = pSMBr->EndOfFile;
1371 pfile_info->NumberOfLinks = cpu_to_le32(1);
1372 pfile_info->DeletePending = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001375
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376 cifs_buf_release(pSMB);
1377 if (rc == -EAGAIN)
1378 goto openRetry;
1379 return rc;
1380}
1381
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382int
Steve French50c2f752007-07-13 00:33:32 +00001383CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
1384 const unsigned int count, const __u64 lseek, unsigned int *nbytes,
1385 char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386{
1387 int rc = -EACCES;
1388 READ_REQ *pSMB = NULL;
1389 READ_RSP *pSMBr = NULL;
1390 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001391 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001392 int resp_buf_type = 0;
1393 struct kvec iov[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394
Joe Perchesb6b38f72010-04-21 03:50:45 +00001395 cFYI(1, "Reading %d bytes on fid %d", count, netfid);
Steve French790fe572007-07-07 19:25:05 +00001396 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001397 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001398 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001399 wct = 10; /* old style read */
Steve French4c3130e2008-12-09 00:28:16 +00001400 if ((lseek >> 32) > 0) {
1401 /* can not handle this big offset for old */
1402 return -EIO;
1403 }
1404 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405
1406 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001407 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408 if (rc)
1409 return rc;
1410
1411 /* tcon and ses pointer are checked in smb_init */
1412 if (tcon->ses->server == NULL)
1413 return -ECONNABORTED;
1414
Steve Frenchec637e32005-12-12 20:53:18 -08001415 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416 pSMB->Fid = netfid;
1417 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001418 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001419 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001420
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421 pSMB->Remaining = 0;
1422 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1423 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001424 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001425 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1426 else {
1427 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001428 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001429 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001430 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001431 }
Steve Frenchec637e32005-12-12 20:53:18 -08001432
1433 iov[0].iov_base = (char *)pSMB;
1434 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
Steve Frencha761ac52007-10-18 21:45:27 +00001435 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Jeff Layton77499812011-01-11 07:24:23 -05001436 &resp_buf_type, CIFS_LOG_ERROR);
Steve Frencha4544342005-08-24 13:59:35 -07001437 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001438 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001440 cERROR(1, "Send error in read = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001441 } else {
1442 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1443 data_length = data_length << 16;
1444 data_length += le16_to_cpu(pSMBr->DataLength);
1445 *nbytes = data_length;
1446
1447 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001448 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449 || (data_length > count)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001450 cFYI(1, "bad length %d for count %d",
1451 data_length, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452 rc = -EIO;
1453 *nbytes = 0;
1454 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001455 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001456 le16_to_cpu(pSMBr->DataOffset);
1457/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001458 cERROR(1, "Faulting on read rc = %d",rc);
Steve French50c2f752007-07-13 00:33:32 +00001459 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001460 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001461 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001462 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463 }
1464 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465
Steve French4b8f9302006-02-26 16:41:18 +00001466/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001467 if (*buf) {
1468 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001469 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001470 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001471 cifs_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001472 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001473 /* return buffer to caller to free */
1474 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001475 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001476 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001477 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001478 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001479 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001480
1481 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482 since file handle passed in no longer valid */
1483 return rc;
1484}
1485
Steve Frenchec637e32005-12-12 20:53:18 -08001486
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487int
1488CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1489 const int netfid, const unsigned int count,
1490 const __u64 offset, unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001491 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492{
1493 int rc = -EACCES;
1494 WRITE_REQ *pSMB = NULL;
1495 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001496 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497 __u32 bytes_sent;
1498 __u16 byte_count;
1499
Steve Frencha24e2d72010-04-03 17:20:21 +00001500 *nbytes = 0;
1501
Joe Perchesb6b38f72010-04-21 03:50:45 +00001502 /* cFYI(1, "write at %lld %d bytes", offset, count);*/
Steve French790fe572007-07-07 19:25:05 +00001503 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001504 return -ECONNABORTED;
1505
Steve French790fe572007-07-07 19:25:05 +00001506 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001507 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001508 else {
Steve French1c955182005-08-30 20:58:07 -07001509 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001510 if ((offset >> 32) > 0) {
1511 /* can not handle big offset for old srv */
1512 return -EIO;
1513 }
1514 }
Steve French1c955182005-08-30 20:58:07 -07001515
1516 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517 (void **) &pSMBr);
1518 if (rc)
1519 return rc;
1520 /* tcon and ses pointer are checked in smb_init */
1521 if (tcon->ses->server == NULL)
1522 return -ECONNABORTED;
1523
1524 pSMB->AndXCommand = 0xFF; /* none */
1525 pSMB->Fid = netfid;
1526 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001527 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001528 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001529
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530 pSMB->Reserved = 0xFFFFFFFF;
1531 pSMB->WriteMode = 0;
1532 pSMB->Remaining = 0;
1533
Steve French50c2f752007-07-13 00:33:32 +00001534 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535 can send more if LARGE_WRITE_X capability returned by the server and if
1536 our buffer is big enough or if we convert to iovecs on socket writes
1537 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001538 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1540 } else {
1541 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1542 & ~0xFF;
1543 }
1544
1545 if (bytes_sent > count)
1546 bytes_sent = count;
1547 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001548 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001549 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001550 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001551 else if (ubuf) {
1552 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553 cifs_buf_release(pSMB);
1554 return -EFAULT;
1555 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001556 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557 /* No buffer */
1558 cifs_buf_release(pSMB);
1559 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001560 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001561 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001562 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001563 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001564 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001565
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1567 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenche30dcf32005-09-20 20:49:16 -07001568 pSMB->hdr.smb_buf_length += byte_count;
Steve French1c955182005-08-30 20:58:07 -07001569
Steve French790fe572007-07-07 19:25:05 +00001570 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001571 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001572 else { /* old style write has byte count 4 bytes earlier
1573 so 4 bytes pad */
1574 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001575 (struct smb_com_writex_req *)pSMB;
1576 pSMBW->ByteCount = cpu_to_le16(byte_count);
1577 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578
1579 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1580 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001581 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00001583 cFYI(1, "Send error in write = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584 } else {
1585 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1586 *nbytes = (*nbytes) << 16;
1587 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301588
1589 /*
1590 * Mask off high 16 bits when bytes written as returned by the
1591 * server is greater than bytes requested by the client. Some
1592 * OS/2 servers are known to set incorrect CountHigh values.
1593 */
1594 if (*nbytes > count)
1595 *nbytes &= 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596 }
1597
1598 cifs_buf_release(pSMB);
1599
Steve French50c2f752007-07-13 00:33:32 +00001600 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601 since file handle passed in no longer valid */
1602
1603 return rc;
1604}
1605
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001606int
1607CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608 const int netfid, const unsigned int count,
Steve French3e844692005-10-03 13:37:24 -07001609 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1610 int n_vec, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611{
1612 int rc = -EACCES;
1613 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001614 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001615 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001616 int resp_buf_type = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001617
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001618 *nbytes = 0;
1619
Joe Perchesb6b38f72010-04-21 03:50:45 +00001620 cFYI(1, "write2 at %lld %d bytes", (long long)offset, count);
Steve Frenchff7feac2005-11-15 16:45:16 -08001621
Steve French4c3130e2008-12-09 00:28:16 +00001622 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07001623 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001624 } else {
Steve French8cc64c62005-10-03 13:49:43 -07001625 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001626 if ((offset >> 32) > 0) {
1627 /* can not handle big offset for old srv */
1628 return -EIO;
1629 }
1630 }
Steve French8cc64c62005-10-03 13:49:43 -07001631 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001632 if (rc)
1633 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634 /* tcon and ses pointer are checked in smb_init */
1635 if (tcon->ses->server == NULL)
1636 return -ECONNABORTED;
1637
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001638 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639 pSMB->Fid = netfid;
1640 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001641 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001642 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643 pSMB->Reserved = 0xFFFFFFFF;
1644 pSMB->WriteMode = 0;
1645 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001646
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001648 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649
Steve French3e844692005-10-03 13:37:24 -07001650 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1651 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001652 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
Steve French790fe572007-07-07 19:25:05 +00001653 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001654 pSMB->hdr.smb_buf_length += count+1;
1655 else /* wct == 12 */
Steve French790fe572007-07-07 19:25:05 +00001656 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1657 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001658 pSMB->ByteCount = cpu_to_le16(count + 1);
1659 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00001660 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07001661 (struct smb_com_writex_req *)pSMB;
1662 pSMBW->ByteCount = cpu_to_le16(count + 5);
1663 }
Steve French3e844692005-10-03 13:37:24 -07001664 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00001665 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08001666 iov[0].iov_len = smb_hdr_len + 4;
1667 else /* wct == 12 pad bigger by four bytes */
1668 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00001669
Steve French3e844692005-10-03 13:37:24 -07001670
Steve Frenchec637e32005-12-12 20:53:18 -08001671 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French133672e2007-11-13 22:41:37 +00001672 long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001673 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001675 cFYI(1, "Send error Write2 = %d", rc);
Steve French790fe572007-07-07 19:25:05 +00001676 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08001677 /* presumably this can not happen, but best to be safe */
1678 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001679 } else {
Steve Frenchad7a2922008-02-07 23:25:02 +00001680 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001681 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1682 *nbytes = (*nbytes) << 16;
1683 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301684
1685 /*
1686 * Mask off high 16 bits when bytes written as returned by the
1687 * server is greater than bytes requested by the client. OS/2
1688 * servers are known to set incorrect CountHigh values.
1689 */
1690 if (*nbytes > count)
1691 *nbytes &= 0xFFFF;
Steve French50c2f752007-07-13 00:33:32 +00001692 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693
Steve French4b8f9302006-02-26 16:41:18 +00001694/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001695 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001696 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001697 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001698 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699
Steve French50c2f752007-07-13 00:33:32 +00001700 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701 since file handle passed in no longer valid */
1702
1703 return rc;
1704}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001705
1706
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707int
1708CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1709 const __u16 smb_file_id, const __u64 len,
1710 const __u64 offset, const __u32 numUnlock,
Pavel Shilovsky12fed002011-01-17 20:15:44 +03001711 const __u32 numLock, const __u8 lockType,
1712 const bool waitFlag, const __u8 oplock_level)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713{
1714 int rc = 0;
1715 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00001716/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717 int bytes_returned;
1718 int timeout = 0;
1719 __u16 count;
1720
Joe Perchesb6b38f72010-04-21 03:50:45 +00001721 cFYI(1, "CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock);
Steve French46810cb2005-04-28 22:41:09 -07001722 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1723
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724 if (rc)
1725 return rc;
1726
Steve French790fe572007-07-07 19:25:05 +00001727 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Steve French133672e2007-11-13 22:41:37 +00001728 timeout = CIFS_ASYNC_OP; /* no response expected */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00001730 } else if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00001731 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1733 } else {
1734 pSMB->Timeout = 0;
1735 }
1736
1737 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1738 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1739 pSMB->LockType = lockType;
Pavel Shilovsky12fed002011-01-17 20:15:44 +03001740 pSMB->OplockLevel = oplock_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741 pSMB->AndXCommand = 0xFF; /* none */
1742 pSMB->Fid = smb_file_id; /* netfid stays le */
1743
Steve French790fe572007-07-07 19:25:05 +00001744 if ((numLock != 0) || (numUnlock != 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1746 /* BB where to store pid high? */
1747 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1748 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1749 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1750 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1751 count = sizeof(LOCKING_ANDX_RANGE);
1752 } else {
1753 /* oplock break */
1754 count = 0;
1755 }
1756 pSMB->hdr.smb_buf_length += count;
1757 pSMB->ByteCount = cpu_to_le16(count);
1758
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001759 if (waitFlag) {
1760 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00001761 (struct smb_hdr *) pSMB, &bytes_returned);
Steve French133672e2007-11-13 22:41:37 +00001762 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001763 } else {
Steve French133672e2007-11-13 22:41:37 +00001764 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
1765 timeout);
1766 /* SMB buffer freed by function above */
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001767 }
Steve Frencha4544342005-08-24 13:59:35 -07001768 cifs_stats_inc(&tcon->num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00001769 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001770 cFYI(1, "Send error in Lock = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771
Steve French50c2f752007-07-13 00:33:32 +00001772 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773 since file handle passed in no longer valid */
1774 return rc;
1775}
1776
1777int
Steve French08547b02006-02-28 22:39:25 +00001778CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1779 const __u16 smb_file_id, const int get_flag, const __u64 len,
Steve French50c2f752007-07-13 00:33:32 +00001780 struct file_lock *pLockData, const __u16 lock_type,
Steve French4b18f2a2008-04-29 00:06:05 +00001781 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00001782{
1783 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1784 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00001785 struct cifs_posix_lock *parm_data;
1786 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00001787 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00001788 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00001789 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00001790 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00001791 struct kvec iov[1];
Steve French08547b02006-02-28 22:39:25 +00001792
Joe Perchesb6b38f72010-04-21 03:50:45 +00001793 cFYI(1, "Posix Lock");
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001794
Steve French790fe572007-07-07 19:25:05 +00001795 if (pLockData == NULL)
Marcin Slusarzed5f0372008-05-13 04:01:01 +00001796 return -EINVAL;
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001797
Steve French08547b02006-02-28 22:39:25 +00001798 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1799
1800 if (rc)
1801 return rc;
1802
1803 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1804
Steve French50c2f752007-07-13 00:33:32 +00001805 params = 6;
Steve French08547b02006-02-28 22:39:25 +00001806 pSMB->MaxSetupCount = 0;
1807 pSMB->Reserved = 0;
1808 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00001809 pSMB->Reserved2 = 0;
1810 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1811 offset = param_offset + params;
1812
Steve French08547b02006-02-28 22:39:25 +00001813 count = sizeof(struct cifs_posix_lock);
1814 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00001815 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00001816 pSMB->SetupCount = 1;
1817 pSMB->Reserved3 = 0;
Steve French790fe572007-07-07 19:25:05 +00001818 if (get_flag)
Steve French08547b02006-02-28 22:39:25 +00001819 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1820 else
1821 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1822 byte_count = 3 /* pad */ + params + count;
1823 pSMB->DataCount = cpu_to_le16(count);
1824 pSMB->ParameterCount = cpu_to_le16(params);
1825 pSMB->TotalDataCount = pSMB->DataCount;
1826 pSMB->TotalParameterCount = pSMB->ParameterCount;
1827 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00001828 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00001829 (((char *) &pSMB->hdr.Protocol) + offset);
1830
1831 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00001832 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00001833 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00001834 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00001835 pSMB->Timeout = cpu_to_le32(-1);
1836 } else
1837 pSMB->Timeout = 0;
1838
Steve French08547b02006-02-28 22:39:25 +00001839 parm_data->pid = cpu_to_le32(current->tgid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001840 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00001841 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00001842
1843 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00001844 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00001845 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1846 pSMB->Reserved4 = 0;
1847 pSMB->hdr.smb_buf_length += byte_count;
1848 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001849 if (waitFlag) {
1850 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1851 (struct smb_hdr *) pSMBr, &bytes_returned);
1852 } else {
Steve French133672e2007-11-13 22:41:37 +00001853 iov[0].iov_base = (char *)pSMB;
1854 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1855 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1856 &resp_buf_type, timeout);
1857 pSMB = NULL; /* request buf already freed by SendReceive2. Do
1858 not try to free it twice below on exit */
1859 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001860 }
1861
Steve French08547b02006-02-28 22:39:25 +00001862 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001863 cFYI(1, "Send error in Posix Lock = %d", rc);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001864 } else if (get_flag) {
1865 /* lock structure can be returned on get */
1866 __u16 data_offset;
1867 __u16 data_count;
1868 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00001869
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001870 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1871 rc = -EIO; /* bad smb */
1872 goto plk_err_exit;
1873 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001874 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1875 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00001876 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001877 rc = -EIO;
1878 goto plk_err_exit;
1879 }
1880 parm_data = (struct cifs_posix_lock *)
1881 ((char *)&pSMBr->hdr.Protocol + data_offset);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04001882 if (parm_data->lock_type == __constant_cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001883 pLockData->fl_type = F_UNLCK;
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04001884 else {
1885 if (parm_data->lock_type ==
1886 __constant_cpu_to_le16(CIFS_RDLCK))
1887 pLockData->fl_type = F_RDLCK;
1888 else if (parm_data->lock_type ==
1889 __constant_cpu_to_le16(CIFS_WRLCK))
1890 pLockData->fl_type = F_WRLCK;
1891
1892 pLockData->fl_start = parm_data->start;
1893 pLockData->fl_end = parm_data->start +
1894 parm_data->length - 1;
1895 pLockData->fl_pid = parm_data->pid;
1896 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001897 }
Steve French50c2f752007-07-13 00:33:32 +00001898
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001899plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00001900 if (pSMB)
1901 cifs_small_buf_release(pSMB);
1902
Steve French133672e2007-11-13 22:41:37 +00001903 if (resp_buf_type == CIFS_SMALL_BUFFER)
1904 cifs_small_buf_release(iov[0].iov_base);
1905 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1906 cifs_buf_release(iov[0].iov_base);
1907
Steve French08547b02006-02-28 22:39:25 +00001908 /* Note: On -EAGAIN error only caller can retry on handle based calls
1909 since file handle passed in no longer valid */
1910
1911 return rc;
1912}
1913
1914
1915int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001916CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1917{
1918 int rc = 0;
1919 CLOSE_REQ *pSMB = NULL;
Joe Perchesb6b38f72010-04-21 03:50:45 +00001920 cFYI(1, "In CIFSSMBClose");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001921
1922/* do not retry on dead session on close */
1923 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00001924 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925 return 0;
1926 if (rc)
1927 return rc;
1928
Linus Torvalds1da177e2005-04-16 15:20:36 -07001929 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00001930 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00001932 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001933 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001934 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00001935 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936 /* EINTR is expected when user ctl-c to kill app */
Joe Perchesb6b38f72010-04-21 03:50:45 +00001937 cERROR(1, "Send error in Close = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938 }
1939 }
1940
Linus Torvalds1da177e2005-04-16 15:20:36 -07001941 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00001942 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943 rc = 0;
1944
1945 return rc;
1946}
1947
1948int
Steve Frenchb298f222009-02-21 21:17:43 +00001949CIFSSMBFlush(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1950{
1951 int rc = 0;
1952 FLUSH_REQ *pSMB = NULL;
Joe Perchesb6b38f72010-04-21 03:50:45 +00001953 cFYI(1, "In CIFSSMBFlush");
Steve Frenchb298f222009-02-21 21:17:43 +00001954
1955 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
1956 if (rc)
1957 return rc;
1958
1959 pSMB->FileID = (__u16) smb_file_id;
1960 pSMB->ByteCount = 0;
1961 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
1962 cifs_stats_inc(&tcon->num_flushes);
1963 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001964 cERROR(1, "Send error in Flush = %d", rc);
Steve Frenchb298f222009-02-21 21:17:43 +00001965
1966 return rc;
1967}
1968
1969int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1971 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001972 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001973{
1974 int rc = 0;
1975 RENAME_REQ *pSMB = NULL;
1976 RENAME_RSP *pSMBr = NULL;
1977 int bytes_returned;
1978 int name_len, name_len2;
1979 __u16 count;
1980
Joe Perchesb6b38f72010-04-21 03:50:45 +00001981 cFYI(1, "In CIFSSMBRename");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982renameRetry:
1983 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1984 (void **) &pSMBr);
1985 if (rc)
1986 return rc;
1987
1988 pSMB->BufferFormat = 0x04;
1989 pSMB->SearchAttributes =
1990 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1991 ATTR_DIRECTORY);
1992
1993 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1994 name_len =
Steve French50c2f752007-07-13 00:33:32 +00001995 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001996 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997 name_len++; /* trailing null */
1998 name_len *= 2;
1999 pSMB->OldFileName[name_len] = 0x04; /* pad */
2000 /* protocol requires ASCII signature byte on Unicode string */
2001 pSMB->OldFileName[name_len + 1] = 0x00;
2002 name_len2 =
Steve French582d21e2008-05-13 04:54:12 +00002003 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002004 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2006 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002007 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002008 name_len = strnlen(fromName, PATH_MAX);
2009 name_len++; /* trailing null */
2010 strncpy(pSMB->OldFileName, fromName, name_len);
2011 name_len2 = strnlen(toName, PATH_MAX);
2012 name_len2++; /* trailing null */
2013 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2014 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2015 name_len2++; /* trailing null */
2016 name_len2++; /* signature byte */
2017 }
2018
2019 count = 1 /* 1st signature byte */ + name_len + name_len2;
2020 pSMB->hdr.smb_buf_length += count;
2021 pSMB->ByteCount = cpu_to_le16(count);
2022
2023 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2024 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002025 cifs_stats_inc(&tcon->num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002026 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002027 cFYI(1, "Send error in rename = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002028
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029 cifs_buf_release(pSMB);
2030
2031 if (rc == -EAGAIN)
2032 goto renameRetry;
2033
2034 return rc;
2035}
2036
Steve French50c2f752007-07-13 00:33:32 +00002037int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002038 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002039 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002040{
2041 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2042 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002043 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002044 char *data_offset;
2045 char dummy_string[30];
2046 int rc = 0;
2047 int bytes_returned = 0;
2048 int len_of_str;
2049 __u16 params, param_offset, offset, count, byte_count;
2050
Joe Perchesb6b38f72010-04-21 03:50:45 +00002051 cFYI(1, "Rename to File by handle");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002052 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2053 (void **) &pSMBr);
2054 if (rc)
2055 return rc;
2056
2057 params = 6;
2058 pSMB->MaxSetupCount = 0;
2059 pSMB->Reserved = 0;
2060 pSMB->Flags = 0;
2061 pSMB->Timeout = 0;
2062 pSMB->Reserved2 = 0;
2063 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2064 offset = param_offset + params;
2065
2066 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2067 rename_info = (struct set_file_rename *) data_offset;
2068 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002069 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002070 pSMB->SetupCount = 1;
2071 pSMB->Reserved3 = 0;
2072 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2073 byte_count = 3 /* pad */ + params;
2074 pSMB->ParameterCount = cpu_to_le16(params);
2075 pSMB->TotalParameterCount = pSMB->ParameterCount;
2076 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2077 pSMB->DataOffset = cpu_to_le16(offset);
2078 /* construct random name ".cifs_tmp<inodenum><mid>" */
2079 rename_info->overwrite = cpu_to_le32(1);
2080 rename_info->root_fid = 0;
2081 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002082 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002083 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
2084 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002085 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002086 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05002087 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002088 target_name, PATH_MAX, nls_codepage,
2089 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002090 }
2091 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002092 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002093 byte_count += count;
2094 pSMB->DataCount = cpu_to_le16(count);
2095 pSMB->TotalDataCount = pSMB->DataCount;
2096 pSMB->Fid = netfid;
2097 pSMB->InformationLevel =
2098 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2099 pSMB->Reserved4 = 0;
2100 pSMB->hdr.smb_buf_length += byte_count;
2101 pSMB->ByteCount = cpu_to_le16(byte_count);
2102 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002103 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002104 cifs_stats_inc(&pTcon->num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002105 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002106 cFYI(1, "Send error in Rename (by file handle) = %d", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07002107
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108 cifs_buf_release(pSMB);
2109
2110 /* Note: On -EAGAIN error only caller can retry on handle based calls
2111 since file handle passed in no longer valid */
2112
2113 return rc;
2114}
2115
2116int
Steve French50c2f752007-07-13 00:33:32 +00002117CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName,
2118 const __u16 target_tid, const char *toName, const int flags,
2119 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002120{
2121 int rc = 0;
2122 COPY_REQ *pSMB = NULL;
2123 COPY_RSP *pSMBr = NULL;
2124 int bytes_returned;
2125 int name_len, name_len2;
2126 __u16 count;
2127
Joe Perchesb6b38f72010-04-21 03:50:45 +00002128 cFYI(1, "In CIFSSMBCopy");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002129copyRetry:
2130 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2131 (void **) &pSMBr);
2132 if (rc)
2133 return rc;
2134
2135 pSMB->BufferFormat = 0x04;
2136 pSMB->Tid2 = target_tid;
2137
2138 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2139
2140 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00002141 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07002142 fromName, PATH_MAX, nls_codepage,
2143 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002144 name_len++; /* trailing null */
2145 name_len *= 2;
2146 pSMB->OldFileName[name_len] = 0x04; /* pad */
2147 /* protocol requires ASCII signature byte on Unicode string */
2148 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002149 name_len2 =
2150 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002151 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002152 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2153 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002154 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002155 name_len = strnlen(fromName, PATH_MAX);
2156 name_len++; /* trailing null */
2157 strncpy(pSMB->OldFileName, fromName, name_len);
2158 name_len2 = strnlen(toName, PATH_MAX);
2159 name_len2++; /* trailing null */
2160 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2161 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2162 name_len2++; /* trailing null */
2163 name_len2++; /* signature byte */
2164 }
2165
2166 count = 1 /* 1st signature byte */ + name_len + name_len2;
2167 pSMB->hdr.smb_buf_length += count;
2168 pSMB->ByteCount = cpu_to_le16(count);
2169
2170 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2171 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2172 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002173 cFYI(1, "Send error in copy = %d with %d files copied",
2174 rc, le16_to_cpu(pSMBr->CopyCount));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175 }
Steve French0d817bc2008-05-22 02:02:03 +00002176 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002177
2178 if (rc == -EAGAIN)
2179 goto copyRetry;
2180
2181 return rc;
2182}
2183
2184int
2185CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
2186 const char *fromName, const char *toName,
2187 const struct nls_table *nls_codepage)
2188{
2189 TRANSACTION2_SPI_REQ *pSMB = NULL;
2190 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2191 char *data_offset;
2192 int name_len;
2193 int name_len_target;
2194 int rc = 0;
2195 int bytes_returned = 0;
2196 __u16 params, param_offset, offset, byte_count;
2197
Joe Perchesb6b38f72010-04-21 03:50:45 +00002198 cFYI(1, "In Symlink Unix style");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002199createSymLinkRetry:
2200 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2201 (void **) &pSMBr);
2202 if (rc)
2203 return rc;
2204
2205 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2206 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002207 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002208 /* find define for this maxpathcomponent */
2209 , nls_codepage);
2210 name_len++; /* trailing null */
2211 name_len *= 2;
2212
Steve French50c2f752007-07-13 00:33:32 +00002213 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002214 name_len = strnlen(fromName, PATH_MAX);
2215 name_len++; /* trailing null */
2216 strncpy(pSMB->FileName, fromName, name_len);
2217 }
2218 params = 6 + name_len;
2219 pSMB->MaxSetupCount = 0;
2220 pSMB->Reserved = 0;
2221 pSMB->Flags = 0;
2222 pSMB->Timeout = 0;
2223 pSMB->Reserved2 = 0;
2224 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002225 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002226 offset = param_offset + params;
2227
2228 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2229 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2230 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08002231 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232 /* find define for this maxpathcomponent */
2233 , nls_codepage);
2234 name_len_target++; /* trailing null */
2235 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002236 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002237 name_len_target = strnlen(toName, PATH_MAX);
2238 name_len_target++; /* trailing null */
2239 strncpy(data_offset, toName, name_len_target);
2240 }
2241
2242 pSMB->MaxParameterCount = cpu_to_le16(2);
2243 /* BB find exact max on data count below from sess */
2244 pSMB->MaxDataCount = cpu_to_le16(1000);
2245 pSMB->SetupCount = 1;
2246 pSMB->Reserved3 = 0;
2247 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2248 byte_count = 3 /* pad */ + params + name_len_target;
2249 pSMB->DataCount = cpu_to_le16(name_len_target);
2250 pSMB->ParameterCount = cpu_to_le16(params);
2251 pSMB->TotalDataCount = pSMB->DataCount;
2252 pSMB->TotalParameterCount = pSMB->ParameterCount;
2253 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2254 pSMB->DataOffset = cpu_to_le16(offset);
2255 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2256 pSMB->Reserved4 = 0;
2257 pSMB->hdr.smb_buf_length += byte_count;
2258 pSMB->ByteCount = cpu_to_le16(byte_count);
2259 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2260 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002261 cifs_stats_inc(&tcon->num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002262 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002263 cFYI(1, "Send error in SetPathInfo create symlink = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002264
Steve French0d817bc2008-05-22 02:02:03 +00002265 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002266
2267 if (rc == -EAGAIN)
2268 goto createSymLinkRetry;
2269
2270 return rc;
2271}
2272
2273int
2274CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2275 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002276 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002277{
2278 TRANSACTION2_SPI_REQ *pSMB = NULL;
2279 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2280 char *data_offset;
2281 int name_len;
2282 int name_len_target;
2283 int rc = 0;
2284 int bytes_returned = 0;
2285 __u16 params, param_offset, offset, byte_count;
2286
Joe Perchesb6b38f72010-04-21 03:50:45 +00002287 cFYI(1, "In Create Hard link Unix style");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002288createHardLinkRetry:
2289 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2290 (void **) &pSMBr);
2291 if (rc)
2292 return rc;
2293
2294 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05002295 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07002296 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002297 name_len++; /* trailing null */
2298 name_len *= 2;
2299
Steve French50c2f752007-07-13 00:33:32 +00002300 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002301 name_len = strnlen(toName, PATH_MAX);
2302 name_len++; /* trailing null */
2303 strncpy(pSMB->FileName, toName, name_len);
2304 }
2305 params = 6 + name_len;
2306 pSMB->MaxSetupCount = 0;
2307 pSMB->Reserved = 0;
2308 pSMB->Flags = 0;
2309 pSMB->Timeout = 0;
2310 pSMB->Reserved2 = 0;
2311 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002312 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002313 offset = param_offset + params;
2314
2315 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2316 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2317 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05002318 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07002319 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002320 name_len_target++; /* trailing null */
2321 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002322 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323 name_len_target = strnlen(fromName, PATH_MAX);
2324 name_len_target++; /* trailing null */
2325 strncpy(data_offset, fromName, name_len_target);
2326 }
2327
2328 pSMB->MaxParameterCount = cpu_to_le16(2);
2329 /* BB find exact max on data count below from sess*/
2330 pSMB->MaxDataCount = cpu_to_le16(1000);
2331 pSMB->SetupCount = 1;
2332 pSMB->Reserved3 = 0;
2333 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2334 byte_count = 3 /* pad */ + params + name_len_target;
2335 pSMB->ParameterCount = cpu_to_le16(params);
2336 pSMB->TotalParameterCount = pSMB->ParameterCount;
2337 pSMB->DataCount = cpu_to_le16(name_len_target);
2338 pSMB->TotalDataCount = pSMB->DataCount;
2339 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2340 pSMB->DataOffset = cpu_to_le16(offset);
2341 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2342 pSMB->Reserved4 = 0;
2343 pSMB->hdr.smb_buf_length += byte_count;
2344 pSMB->ByteCount = cpu_to_le16(byte_count);
2345 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2346 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002347 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002348 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002349 cFYI(1, "Send error in SetPathInfo (hard link) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002350
2351 cifs_buf_release(pSMB);
2352 if (rc == -EAGAIN)
2353 goto createHardLinkRetry;
2354
2355 return rc;
2356}
2357
2358int
2359CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2360 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002361 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002362{
2363 int rc = 0;
2364 NT_RENAME_REQ *pSMB = NULL;
2365 RENAME_RSP *pSMBr = NULL;
2366 int bytes_returned;
2367 int name_len, name_len2;
2368 __u16 count;
2369
Joe Perchesb6b38f72010-04-21 03:50:45 +00002370 cFYI(1, "In CIFSCreateHardLink");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002371winCreateHardLinkRetry:
2372
2373 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2374 (void **) &pSMBr);
2375 if (rc)
2376 return rc;
2377
2378 pSMB->SearchAttributes =
2379 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2380 ATTR_DIRECTORY);
2381 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2382 pSMB->ClusterCount = 0;
2383
2384 pSMB->BufferFormat = 0x04;
2385
2386 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2387 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002388 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002389 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002390 name_len++; /* trailing null */
2391 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05002392
2393 /* protocol specifies ASCII buffer format (0x04) for unicode */
2394 pSMB->OldFileName[name_len] = 0x04;
2395 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002396 name_len2 =
Steve French50c2f752007-07-13 00:33:32 +00002397 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002398 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002399 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2400 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002401 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002402 name_len = strnlen(fromName, PATH_MAX);
2403 name_len++; /* trailing null */
2404 strncpy(pSMB->OldFileName, fromName, name_len);
2405 name_len2 = strnlen(toName, PATH_MAX);
2406 name_len2++; /* trailing null */
2407 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2408 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2409 name_len2++; /* trailing null */
2410 name_len2++; /* signature byte */
2411 }
2412
2413 count = 1 /* string type byte */ + name_len + name_len2;
2414 pSMB->hdr.smb_buf_length += count;
2415 pSMB->ByteCount = cpu_to_le16(count);
2416
2417 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2418 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002419 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002420 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002421 cFYI(1, "Send error in hard link (NT rename) = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00002422
Linus Torvalds1da177e2005-04-16 15:20:36 -07002423 cifs_buf_release(pSMB);
2424 if (rc == -EAGAIN)
2425 goto winCreateHardLinkRetry;
2426
2427 return rc;
2428}
2429
2430int
2431CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04002432 const unsigned char *searchName, char **symlinkinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002433 const struct nls_table *nls_codepage)
2434{
2435/* SMB_QUERY_FILE_UNIX_LINK */
2436 TRANSACTION2_QPI_REQ *pSMB = NULL;
2437 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2438 int rc = 0;
2439 int bytes_returned;
2440 int name_len;
2441 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04002442 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002443
Joe Perchesb6b38f72010-04-21 03:50:45 +00002444 cFYI(1, "In QPathSymLinkInfo (Unix) for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002445
2446querySymLinkRetry:
2447 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2448 (void **) &pSMBr);
2449 if (rc)
2450 return rc;
2451
2452 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2453 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002454 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
2455 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002456 name_len++; /* trailing null */
2457 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002458 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002459 name_len = strnlen(searchName, PATH_MAX);
2460 name_len++; /* trailing null */
2461 strncpy(pSMB->FileName, searchName, name_len);
2462 }
2463
2464 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2465 pSMB->TotalDataCount = 0;
2466 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04002467 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002468 pSMB->MaxSetupCount = 0;
2469 pSMB->Reserved = 0;
2470 pSMB->Flags = 0;
2471 pSMB->Timeout = 0;
2472 pSMB->Reserved2 = 0;
2473 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00002474 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002475 pSMB->DataCount = 0;
2476 pSMB->DataOffset = 0;
2477 pSMB->SetupCount = 1;
2478 pSMB->Reserved3 = 0;
2479 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2480 byte_count = params + 1 /* pad */ ;
2481 pSMB->TotalParameterCount = cpu_to_le16(params);
2482 pSMB->ParameterCount = pSMB->TotalParameterCount;
2483 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2484 pSMB->Reserved4 = 0;
2485 pSMB->hdr.smb_buf_length += byte_count;
2486 pSMB->ByteCount = cpu_to_le16(byte_count);
2487
2488 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2489 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2490 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002491 cFYI(1, "Send error in QuerySymLinkInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002492 } else {
2493 /* decode response */
2494
2495 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002496 /* BB also check enough total bytes returned */
Jeff Layton460b9692009-04-30 07:17:56 -04002497 if (rc || (pSMBr->ByteCount < 2))
2498 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002499 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00002500 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04002501 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002502
Jeff Layton460b9692009-04-30 07:17:56 -04002503 data_start = ((char *) &pSMBr->hdr.Protocol) +
2504 le16_to_cpu(pSMBr->t2.DataOffset);
2505
Steve French0e0d2cf2009-05-01 05:27:32 +00002506 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2507 is_unicode = true;
2508 else
2509 is_unicode = false;
2510
Steve French737b7582005-04-28 22:41:06 -07002511 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchd185cda2009-04-30 17:45:10 +00002512 *symlinkinfo = cifs_strndup_from_ucs(data_start, count,
Steve French0e0d2cf2009-05-01 05:27:32 +00002513 is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04002514 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04002515 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002516 }
2517 }
2518 cifs_buf_release(pSMB);
2519 if (rc == -EAGAIN)
2520 goto querySymLinkRetry;
2521 return rc;
2522}
2523
Parag Warudkarc9489772007-10-23 18:09:48 +00002524#ifdef CONFIG_CIFS_EXPERIMENTAL
Linus Torvalds1da177e2005-04-16 15:20:36 -07002525int
2526CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2527 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00002528 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529 const struct nls_table *nls_codepage)
2530{
2531 int rc = 0;
2532 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00002533 struct smb_com_transaction_ioctl_req *pSMB;
2534 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002535
Joe Perchesb6b38f72010-04-21 03:50:45 +00002536 cFYI(1, "In Windows reparse style QueryLink for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002537 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2538 (void **) &pSMBr);
2539 if (rc)
2540 return rc;
2541
2542 pSMB->TotalParameterCount = 0 ;
2543 pSMB->TotalDataCount = 0;
2544 pSMB->MaxParameterCount = cpu_to_le32(2);
2545 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002546 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2547 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002548 pSMB->MaxSetupCount = 4;
2549 pSMB->Reserved = 0;
2550 pSMB->ParameterOffset = 0;
2551 pSMB->DataCount = 0;
2552 pSMB->DataOffset = 0;
2553 pSMB->SetupCount = 4;
2554 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2555 pSMB->ParameterCount = pSMB->TotalParameterCount;
2556 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2557 pSMB->IsFsctl = 1; /* FSCTL */
2558 pSMB->IsRootFlag = 0;
2559 pSMB->Fid = fid; /* file handle always le */
2560 pSMB->ByteCount = 0;
2561
2562 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2563 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2564 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002565 cFYI(1, "Send error in QueryReparseLinkInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002566 } else { /* decode response */
2567 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2568 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
Steve Frenchafe48c32009-05-02 05:25:46 +00002569 if ((pSMBr->ByteCount < 2) || (data_offset > 512)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002570 /* BB also check enough total bytes returned */
2571 rc = -EIO; /* bad smb */
Steve Frenchafe48c32009-05-02 05:25:46 +00002572 goto qreparse_out;
2573 }
2574 if (data_count && (data_count < 2048)) {
2575 char *end_of_smb = 2 /* sizeof byte count */ +
2576 pSMBr->ByteCount + (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002577
Steve Frenchafe48c32009-05-02 05:25:46 +00002578 struct reparse_data *reparse_buf =
Steve French50c2f752007-07-13 00:33:32 +00002579 (struct reparse_data *)
2580 ((char *)&pSMBr->hdr.Protocol
2581 + data_offset);
Steve Frenchafe48c32009-05-02 05:25:46 +00002582 if ((char *)reparse_buf >= end_of_smb) {
2583 rc = -EIO;
2584 goto qreparse_out;
2585 }
2586 if ((reparse_buf->LinkNamesBuf +
2587 reparse_buf->TargetNameOffset +
2588 reparse_buf->TargetNameLen) > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002589 cFYI(1, "reparse buf beyond SMB");
Steve Frenchafe48c32009-05-02 05:25:46 +00002590 rc = -EIO;
2591 goto qreparse_out;
2592 }
Steve French50c2f752007-07-13 00:33:32 +00002593
Steve Frenchafe48c32009-05-02 05:25:46 +00002594 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2595 cifs_from_ucs2(symlinkinfo, (__le16 *)
Steve French50c2f752007-07-13 00:33:32 +00002596 (reparse_buf->LinkNamesBuf +
2597 reparse_buf->TargetNameOffset),
Steve Frenchafe48c32009-05-02 05:25:46 +00002598 buflen,
2599 reparse_buf->TargetNameLen,
2600 nls_codepage, 0);
2601 } else { /* ASCII names */
2602 strncpy(symlinkinfo,
2603 reparse_buf->LinkNamesBuf +
2604 reparse_buf->TargetNameOffset,
2605 min_t(const int, buflen,
2606 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002607 }
Steve Frenchafe48c32009-05-02 05:25:46 +00002608 } else {
2609 rc = -EIO;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002610 cFYI(1, "Invalid return data count on "
2611 "get reparse info ioctl");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002612 }
Steve Frenchafe48c32009-05-02 05:25:46 +00002613 symlinkinfo[buflen] = 0; /* just in case so the caller
2614 does not go off the end of the buffer */
Joe Perchesb6b38f72010-04-21 03:50:45 +00002615 cFYI(1, "readlink result - %s", symlinkinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002616 }
Steve French989c7e52009-05-02 05:32:20 +00002617
Linus Torvalds1da177e2005-04-16 15:20:36 -07002618qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002619 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002620
2621 /* Note: On -EAGAIN error only caller can retry on handle based calls
2622 since file handle passed in no longer valid */
2623
2624 return rc;
2625}
Steve Frenchafe48c32009-05-02 05:25:46 +00002626#endif /* CIFS_EXPERIMENTAL */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002627
2628#ifdef CONFIG_CIFS_POSIX
2629
2630/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00002631static void cifs_convert_ace(posix_acl_xattr_entry *ace,
2632 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002633{
2634 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002635 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2636 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2637 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesb6b38f72010-04-21 03:50:45 +00002638 /* cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002639
2640 return;
2641}
2642
2643/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00002644static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
2645 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002646{
2647 int size = 0;
2648 int i;
2649 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00002650 struct cifs_posix_ace *pACE;
2651 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
2652 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002653
2654 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2655 return -EOPNOTSUPP;
2656
Steve French790fe572007-07-07 19:25:05 +00002657 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002658 count = le16_to_cpu(cifs_acl->access_entry_count);
2659 pACE = &cifs_acl->ace_array[0];
2660 size = sizeof(struct cifs_posix_acl);
2661 size += sizeof(struct cifs_posix_ace) * count;
2662 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002663 if (size_of_data_area < size) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002664 cFYI(1, "bad CIFS POSIX ACL size %d vs. %d",
2665 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002666 return -EINVAL;
2667 }
Steve French790fe572007-07-07 19:25:05 +00002668 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002669 count = le16_to_cpu(cifs_acl->access_entry_count);
2670 size = sizeof(struct cifs_posix_acl);
2671 size += sizeof(struct cifs_posix_ace) * count;
2672/* skip past access ACEs to get to default ACEs */
2673 pACE = &cifs_acl->ace_array[count];
2674 count = le16_to_cpu(cifs_acl->default_entry_count);
2675 size += sizeof(struct cifs_posix_ace) * count;
2676 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002677 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002678 return -EINVAL;
2679 } else {
2680 /* illegal type */
2681 return -EINVAL;
2682 }
2683
2684 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00002685 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00002686 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00002687 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002688 return -ERANGE;
2689 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002690 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00002691 for (i = 0; i < count ; i++) {
2692 cifs_convert_ace(&local_acl->a_entries[i], pACE);
2693 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002694 }
2695 }
2696 return size;
2697}
2698
Steve French50c2f752007-07-13 00:33:32 +00002699static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
2700 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002701{
2702 __u16 rc = 0; /* 0 = ACL converted ok */
2703
Steve Frenchff7feac2005-11-15 16:45:16 -08002704 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2705 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002706 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00002707 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002708 /* Probably no need to le convert -1 on any arch but can not hurt */
2709 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00002710 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002711 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesb6b38f72010-04-21 03:50:45 +00002712 /*cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id);*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002713 return rc;
2714}
2715
2716/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00002717static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
2718 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002719{
2720 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00002721 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
2722 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002723 int count;
2724 int i;
2725
Steve French790fe572007-07-07 19:25:05 +00002726 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002727 return 0;
2728
2729 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesb6b38f72010-04-21 03:50:45 +00002730 cFYI(1, "setting acl with %d entries from buf of length %d and "
Steve French63135e02007-07-17 17:34:02 +00002731 "version of %d",
Joe Perchesb6b38f72010-04-21 03:50:45 +00002732 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00002733 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002734 cFYI(1, "unknown POSIX ACL version %d",
2735 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002736 return 0;
2737 }
2738 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00002739 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08002740 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00002741 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08002742 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002743 else {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002744 cFYI(1, "unknown ACL type %d", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002745 return 0;
2746 }
Steve French50c2f752007-07-13 00:33:32 +00002747 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2749 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00002750 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002751 /* ACE not converted */
2752 break;
2753 }
2754 }
Steve French790fe572007-07-07 19:25:05 +00002755 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002756 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2757 rc += sizeof(struct cifs_posix_acl);
2758 /* BB add check to make sure ACL does not overflow SMB */
2759 }
2760 return rc;
2761}
2762
2763int
2764CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002765 const unsigned char *searchName,
2766 char *acl_inf, const int buflen, const int acl_type,
2767 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002768{
2769/* SMB_QUERY_POSIX_ACL */
2770 TRANSACTION2_QPI_REQ *pSMB = NULL;
2771 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2772 int rc = 0;
2773 int bytes_returned;
2774 int name_len;
2775 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00002776
Joe Perchesb6b38f72010-04-21 03:50:45 +00002777 cFYI(1, "In GetPosixACL (Unix) for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002778
2779queryAclRetry:
2780 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2781 (void **) &pSMBr);
2782 if (rc)
2783 return rc;
Steve French50c2f752007-07-13 00:33:32 +00002784
Linus Torvalds1da177e2005-04-16 15:20:36 -07002785 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2786 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002787 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002788 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002789 name_len++; /* trailing null */
2790 name_len *= 2;
2791 pSMB->FileName[name_len] = 0;
2792 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00002793 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002794 name_len = strnlen(searchName, PATH_MAX);
2795 name_len++; /* trailing null */
2796 strncpy(pSMB->FileName, searchName, name_len);
2797 }
2798
2799 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2800 pSMB->TotalDataCount = 0;
2801 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00002802 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002803 pSMB->MaxDataCount = cpu_to_le16(4000);
2804 pSMB->MaxSetupCount = 0;
2805 pSMB->Reserved = 0;
2806 pSMB->Flags = 0;
2807 pSMB->Timeout = 0;
2808 pSMB->Reserved2 = 0;
2809 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00002810 offsetof(struct smb_com_transaction2_qpi_req,
2811 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002812 pSMB->DataCount = 0;
2813 pSMB->DataOffset = 0;
2814 pSMB->SetupCount = 1;
2815 pSMB->Reserved3 = 0;
2816 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2817 byte_count = params + 1 /* pad */ ;
2818 pSMB->TotalParameterCount = cpu_to_le16(params);
2819 pSMB->ParameterCount = pSMB->TotalParameterCount;
2820 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2821 pSMB->Reserved4 = 0;
2822 pSMB->hdr.smb_buf_length += byte_count;
2823 pSMB->ByteCount = cpu_to_le16(byte_count);
2824
2825 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2826 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08002827 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002828 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002829 cFYI(1, "Send error in Query POSIX ACL = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002830 } else {
2831 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00002832
Linus Torvalds1da177e2005-04-16 15:20:36 -07002833 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2834 if (rc || (pSMBr->ByteCount < 2))
2835 /* BB also check enough total bytes returned */
2836 rc = -EIO; /* bad smb */
2837 else {
2838 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2839 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2840 rc = cifs_copy_posix_acl(acl_inf,
2841 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00002842 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002843 }
2844 }
2845 cifs_buf_release(pSMB);
2846 if (rc == -EAGAIN)
2847 goto queryAclRetry;
2848 return rc;
2849}
2850
2851int
2852CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002853 const unsigned char *fileName,
2854 const char *local_acl, const int buflen,
2855 const int acl_type,
2856 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002857{
2858 struct smb_com_transaction2_spi_req *pSMB = NULL;
2859 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2860 char *parm_data;
2861 int name_len;
2862 int rc = 0;
2863 int bytes_returned = 0;
2864 __u16 params, byte_count, data_count, param_offset, offset;
2865
Joe Perchesb6b38f72010-04-21 03:50:45 +00002866 cFYI(1, "In SetPosixACL (Unix) for path %s", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002867setAclRetry:
2868 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002869 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002870 if (rc)
2871 return rc;
2872 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2873 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002874 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002875 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002876 name_len++; /* trailing null */
2877 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002878 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002879 name_len = strnlen(fileName, PATH_MAX);
2880 name_len++; /* trailing null */
2881 strncpy(pSMB->FileName, fileName, name_len);
2882 }
2883 params = 6 + name_len;
2884 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00002885 /* BB find max SMB size from sess */
2886 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002887 pSMB->MaxSetupCount = 0;
2888 pSMB->Reserved = 0;
2889 pSMB->Flags = 0;
2890 pSMB->Timeout = 0;
2891 pSMB->Reserved2 = 0;
2892 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002893 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002894 offset = param_offset + params;
2895 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2896 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2897
2898 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00002899 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002900
Steve French790fe572007-07-07 19:25:05 +00002901 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002902 rc = -EOPNOTSUPP;
2903 goto setACLerrorExit;
2904 }
2905 pSMB->DataOffset = cpu_to_le16(offset);
2906 pSMB->SetupCount = 1;
2907 pSMB->Reserved3 = 0;
2908 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2909 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2910 byte_count = 3 /* pad */ + params + data_count;
2911 pSMB->DataCount = cpu_to_le16(data_count);
2912 pSMB->TotalDataCount = pSMB->DataCount;
2913 pSMB->ParameterCount = cpu_to_le16(params);
2914 pSMB->TotalParameterCount = pSMB->ParameterCount;
2915 pSMB->Reserved4 = 0;
2916 pSMB->hdr.smb_buf_length += byte_count;
2917 pSMB->ByteCount = cpu_to_le16(byte_count);
2918 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002919 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00002920 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002921 cFYI(1, "Set POSIX ACL returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002922
2923setACLerrorExit:
2924 cifs_buf_release(pSMB);
2925 if (rc == -EAGAIN)
2926 goto setAclRetry;
2927 return rc;
2928}
2929
Steve Frenchf654bac2005-04-28 22:41:04 -07002930/* BB fix tabs in this function FIXME BB */
2931int
2932CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00002933 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07002934{
Steve French50c2f752007-07-13 00:33:32 +00002935 int rc = 0;
2936 struct smb_t2_qfi_req *pSMB = NULL;
2937 struct smb_t2_qfi_rsp *pSMBr = NULL;
2938 int bytes_returned;
2939 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07002940
Joe Perchesb6b38f72010-04-21 03:50:45 +00002941 cFYI(1, "In GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00002942 if (tcon == NULL)
2943 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07002944
2945GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00002946 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2947 (void **) &pSMBr);
2948 if (rc)
2949 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07002950
Steve Frenchad7a2922008-02-07 23:25:02 +00002951 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00002952 pSMB->t2.TotalDataCount = 0;
2953 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
2954 /* BB find exact max data count below from sess structure BB */
2955 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2956 pSMB->t2.MaxSetupCount = 0;
2957 pSMB->t2.Reserved = 0;
2958 pSMB->t2.Flags = 0;
2959 pSMB->t2.Timeout = 0;
2960 pSMB->t2.Reserved2 = 0;
2961 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2962 Fid) - 4);
2963 pSMB->t2.DataCount = 0;
2964 pSMB->t2.DataOffset = 0;
2965 pSMB->t2.SetupCount = 1;
2966 pSMB->t2.Reserved3 = 0;
2967 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2968 byte_count = params + 1 /* pad */ ;
2969 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2970 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2971 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
2972 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07002973 pSMB->Fid = netfid;
Steve French790fe572007-07-07 19:25:05 +00002974 pSMB->hdr.smb_buf_length += byte_count;
2975 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07002976
Steve French790fe572007-07-07 19:25:05 +00002977 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2978 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2979 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002980 cFYI(1, "error %d in GetExtAttr", rc);
Steve French790fe572007-07-07 19:25:05 +00002981 } else {
2982 /* decode response */
2983 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2984 if (rc || (pSMBr->ByteCount < 2))
2985 /* BB also check enough total bytes returned */
2986 /* If rc should we check for EOPNOSUPP and
2987 disable the srvino flag? or in caller? */
2988 rc = -EIO; /* bad smb */
2989 else {
2990 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2991 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2992 struct file_chattr_info *pfinfo;
2993 /* BB Do we need a cast or hash here ? */
2994 if (count != 16) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002995 cFYI(1, "Illegal size ret in GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00002996 rc = -EIO;
2997 goto GetExtAttrOut;
2998 }
2999 pfinfo = (struct file_chattr_info *)
3000 (data_offset + (char *) &pSMBr->hdr.Protocol);
3001 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003002 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003003 }
3004 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003005GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003006 cifs_buf_release(pSMB);
3007 if (rc == -EAGAIN)
3008 goto GetExtAttrRetry;
3009 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003010}
3011
Steve Frenchf654bac2005-04-28 22:41:04 -07003012#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003013
Jeff Layton79df1ba2010-12-06 12:52:08 -05003014#ifdef CONFIG_CIFS_ACL
3015/*
3016 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3017 * all NT TRANSACTS that we init here have total parm and data under about 400
3018 * bytes (to fit in small cifs buffer size), which is the case so far, it
3019 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3020 * returned setup area) and MaxParameterCount (returned parms size) must be set
3021 * by caller
3022 */
3023static int
3024smb_init_nttransact(const __u16 sub_command, const int setup_count,
3025 const int parm_len, struct cifsTconInfo *tcon,
3026 void **ret_buf)
3027{
3028 int rc;
3029 __u32 temp_offset;
3030 struct smb_com_ntransact_req *pSMB;
3031
3032 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3033 (void **)&pSMB);
3034 if (rc)
3035 return rc;
3036 *ret_buf = (void *)pSMB;
3037 pSMB->Reserved = 0;
3038 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3039 pSMB->TotalDataCount = 0;
3040 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
3041 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3042 pSMB->ParameterCount = pSMB->TotalParameterCount;
3043 pSMB->DataCount = pSMB->TotalDataCount;
3044 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3045 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3046 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3047 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3048 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3049 pSMB->SubCommand = cpu_to_le16(sub_command);
3050 return 0;
3051}
3052
3053static int
3054validate_ntransact(char *buf, char **ppparm, char **ppdata,
3055 __u32 *pparmlen, __u32 *pdatalen)
3056{
3057 char *end_of_smb;
3058 __u32 data_count, data_offset, parm_count, parm_offset;
3059 struct smb_com_ntransact_rsp *pSMBr;
3060
3061 *pdatalen = 0;
3062 *pparmlen = 0;
3063
3064 if (buf == NULL)
3065 return -EINVAL;
3066
3067 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3068
3069 /* ByteCount was converted from little endian in SendReceive */
3070 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
3071 (char *)&pSMBr->ByteCount;
3072
3073 data_offset = le32_to_cpu(pSMBr->DataOffset);
3074 data_count = le32_to_cpu(pSMBr->DataCount);
3075 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3076 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3077
3078 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3079 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3080
3081 /* should we also check that parm and data areas do not overlap? */
3082 if (*ppparm > end_of_smb) {
3083 cFYI(1, "parms start after end of smb");
3084 return -EINVAL;
3085 } else if (parm_count + *ppparm > end_of_smb) {
3086 cFYI(1, "parm end after end of smb");
3087 return -EINVAL;
3088 } else if (*ppdata > end_of_smb) {
3089 cFYI(1, "data starts after end of smb");
3090 return -EINVAL;
3091 } else if (data_count + *ppdata > end_of_smb) {
3092 cFYI(1, "data %p + count %d (%p) past smb end %p start %p",
3093 *ppdata, data_count, (data_count + *ppdata),
3094 end_of_smb, pSMBr);
3095 return -EINVAL;
3096 } else if (parm_count + data_count > pSMBr->ByteCount) {
3097 cFYI(1, "parm count and data count larger than SMB");
3098 return -EINVAL;
3099 }
3100 *pdatalen = data_count;
3101 *pparmlen = parm_count;
3102 return 0;
3103}
3104
Steve French0a4b92c2006-01-12 15:44:21 -08003105/* Get Security Descriptor (by handle) from remote server for a file or dir */
3106int
3107CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003108 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003109{
3110 int rc = 0;
3111 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003112 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003113 struct kvec iov[1];
3114
Joe Perchesb6b38f72010-04-21 03:50:45 +00003115 cFYI(1, "GetCifsACL");
Steve French0a4b92c2006-01-12 15:44:21 -08003116
Steve French630f3f0c2007-10-25 21:17:17 +00003117 *pbuflen = 0;
3118 *acl_inf = NULL;
3119
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003120 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003121 8 /* parm len */, tcon, (void **) &pSMB);
3122 if (rc)
3123 return rc;
3124
3125 pSMB->MaxParameterCount = cpu_to_le32(4);
3126 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3127 pSMB->MaxSetupCount = 0;
3128 pSMB->Fid = fid; /* file handle always le */
3129 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3130 CIFS_ACL_DACL);
3131 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
3132 pSMB->hdr.smb_buf_length += 11;
3133 iov[0].iov_base = (char *)pSMB;
3134 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
3135
Steve Frencha761ac52007-10-18 21:45:27 +00003136 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Jeff Layton77499812011-01-11 07:24:23 -05003137 0);
Steve French0a4b92c2006-01-12 15:44:21 -08003138 cifs_stats_inc(&tcon->num_acl_get);
3139 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003140 cFYI(1, "Send error in QuerySecDesc = %d", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08003141 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003142 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003143 __u32 parm_len;
3144 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003145 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003146 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003147
3148/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003149 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003150 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003151 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003152 goto qsec_out;
3153 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3154
Joe Perchesb6b38f72010-04-21 03:50:45 +00003155 cFYI(1, "smb %p parm %p data %p", pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08003156
3157 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3158 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003159 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003160 goto qsec_out;
3161 }
3162
3163/* BB check that data area is minimum length and as big as acl_len */
3164
Steve Frenchaf6f4612007-10-16 18:40:37 +00003165 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003166 if (acl_len != *pbuflen) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003167 cERROR(1, "acl length %d does not match %d",
3168 acl_len, *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003169 if (*pbuflen > acl_len)
3170 *pbuflen = acl_len;
3171 }
Steve French0a4b92c2006-01-12 15:44:21 -08003172
Steve French630f3f0c2007-10-25 21:17:17 +00003173 /* check if buffer is big enough for the acl
3174 header followed by the smallest SID */
3175 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3176 (*pbuflen >= 64 * 1024)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003177 cERROR(1, "bad acl length %d", *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003178 rc = -EINVAL;
3179 *pbuflen = 0;
3180 } else {
3181 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3182 if (*acl_inf == NULL) {
3183 *pbuflen = 0;
3184 rc = -ENOMEM;
3185 }
3186 memcpy(*acl_inf, pdata, *pbuflen);
3187 }
Steve French0a4b92c2006-01-12 15:44:21 -08003188 }
3189qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003190 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003191 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003192 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003193 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003194/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003195 return rc;
3196}
Steve French97837582007-12-31 07:47:21 +00003197
3198int
3199CIFSSMBSetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3200 struct cifs_ntsd *pntsd, __u32 acllen)
3201{
3202 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3203 int rc = 0;
3204 int bytes_returned = 0;
3205 SET_SEC_DESC_REQ *pSMB = NULL;
3206 NTRANSACT_RSP *pSMBr = NULL;
3207
3208setCifsAclRetry:
3209 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB,
3210 (void **) &pSMBr);
3211 if (rc)
3212 return (rc);
3213
3214 pSMB->MaxSetupCount = 0;
3215 pSMB->Reserved = 0;
3216
3217 param_count = 8;
3218 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3219 data_count = acllen;
3220 data_offset = param_offset + param_count;
3221 byte_count = 3 /* pad */ + param_count;
3222
3223 pSMB->DataCount = cpu_to_le32(data_count);
3224 pSMB->TotalDataCount = pSMB->DataCount;
3225 pSMB->MaxParameterCount = cpu_to_le32(4);
3226 pSMB->MaxDataCount = cpu_to_le32(16384);
3227 pSMB->ParameterCount = cpu_to_le32(param_count);
3228 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3229 pSMB->TotalParameterCount = pSMB->ParameterCount;
3230 pSMB->DataOffset = cpu_to_le32(data_offset);
3231 pSMB->SetupCount = 0;
3232 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3233 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3234
3235 pSMB->Fid = fid; /* file handle always le */
3236 pSMB->Reserved2 = 0;
3237 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_DACL);
3238
3239 if (pntsd && acllen) {
3240 memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
3241 (char *) pntsd,
3242 acllen);
3243 pSMB->hdr.smb_buf_length += (byte_count + data_count);
3244
3245 } else
3246 pSMB->hdr.smb_buf_length += byte_count;
3247
3248 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3249 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3250
Joe Perchesb6b38f72010-04-21 03:50:45 +00003251 cFYI(1, "SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00003252 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003253 cFYI(1, "Set CIFS ACL returned %d", rc);
Steve French97837582007-12-31 07:47:21 +00003254 cifs_buf_release(pSMB);
3255
3256 if (rc == -EAGAIN)
3257 goto setCifsAclRetry;
3258
3259 return (rc);
3260}
3261
Jeff Layton79df1ba2010-12-06 12:52:08 -05003262#endif /* CONFIG_CIFS_ACL */
Steve French0a4b92c2006-01-12 15:44:21 -08003263
Steve French6b8edfe2005-08-23 20:26:03 -07003264/* Legacy Query Path Information call for lookup to old servers such
3265 as Win9x/WinME */
3266int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003267 const unsigned char *searchName,
3268 FILE_ALL_INFO *pFinfo,
3269 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003270{
Steve Frenchad7a2922008-02-07 23:25:02 +00003271 QUERY_INFORMATION_REQ *pSMB;
3272 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003273 int rc = 0;
3274 int bytes_returned;
3275 int name_len;
3276
Joe Perchesb6b38f72010-04-21 03:50:45 +00003277 cFYI(1, "In SMBQPath path %s", searchName);
Steve French6b8edfe2005-08-23 20:26:03 -07003278QInfRetry:
3279 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003280 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003281 if (rc)
3282 return rc;
3283
3284 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3285 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003286 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3287 PATH_MAX, nls_codepage, remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003288 name_len++; /* trailing null */
3289 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003290 } else {
Steve French6b8edfe2005-08-23 20:26:03 -07003291 name_len = strnlen(searchName, PATH_MAX);
3292 name_len++; /* trailing null */
3293 strncpy(pSMB->FileName, searchName, name_len);
3294 }
3295 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003296 name_len++; /* account for buffer type byte */
Steve French6b8edfe2005-08-23 20:26:03 -07003297 pSMB->hdr.smb_buf_length += (__u16) name_len;
3298 pSMB->ByteCount = cpu_to_le16(name_len);
3299
3300 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003301 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003302 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003303 cFYI(1, "Send error in QueryInfo = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00003304 } else if (pFinfo) {
Steve French1bd5bbc2006-09-28 03:35:57 +00003305 struct timespec ts;
3306 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00003307
3308 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003309 /* BB FIXME - add time zone adjustment BB */
Steve French6b8edfe2005-08-23 20:26:03 -07003310 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003311 ts.tv_nsec = 0;
3312 ts.tv_sec = time;
3313 /* decode time fields */
Al Viro733f99a2006-10-14 16:48:26 +01003314 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
Steve French1bd5bbc2006-09-28 03:35:57 +00003315 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3316 pFinfo->LastAccessTime = 0;
Steve French70ca7342005-09-22 16:32:06 -07003317 pFinfo->AllocationSize =
3318 cpu_to_le64(le32_to_cpu(pSMBr->size));
3319 pFinfo->EndOfFile = pFinfo->AllocationSize;
3320 pFinfo->Attributes =
3321 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003322 } else
3323 rc = -EIO; /* bad buffer passed in */
3324
3325 cifs_buf_release(pSMB);
3326
3327 if (rc == -EAGAIN)
3328 goto QInfRetry;
3329
3330 return rc;
3331}
3332
Jeff Laytonbcd53572010-02-12 07:44:16 -05003333int
3334CIFSSMBQFileInfo(const int xid, struct cifsTconInfo *tcon,
3335 u16 netfid, FILE_ALL_INFO *pFindData)
3336{
3337 struct smb_t2_qfi_req *pSMB = NULL;
3338 struct smb_t2_qfi_rsp *pSMBr = NULL;
3339 int rc = 0;
3340 int bytes_returned;
3341 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07003342
Jeff Laytonbcd53572010-02-12 07:44:16 -05003343QFileInfoRetry:
3344 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3345 (void **) &pSMBr);
3346 if (rc)
3347 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07003348
Jeff Laytonbcd53572010-02-12 07:44:16 -05003349 params = 2 /* level */ + 2 /* fid */;
3350 pSMB->t2.TotalDataCount = 0;
3351 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3352 /* BB find exact max data count below from sess structure BB */
3353 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3354 pSMB->t2.MaxSetupCount = 0;
3355 pSMB->t2.Reserved = 0;
3356 pSMB->t2.Flags = 0;
3357 pSMB->t2.Timeout = 0;
3358 pSMB->t2.Reserved2 = 0;
3359 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3360 Fid) - 4);
3361 pSMB->t2.DataCount = 0;
3362 pSMB->t2.DataOffset = 0;
3363 pSMB->t2.SetupCount = 1;
3364 pSMB->t2.Reserved3 = 0;
3365 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3366 byte_count = params + 1 /* pad */ ;
3367 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3368 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3369 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3370 pSMB->Pad = 0;
3371 pSMB->Fid = netfid;
3372 pSMB->hdr.smb_buf_length += byte_count;
3373
3374 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3375 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3376 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00003377 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003378 } else { /* decode response */
3379 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3380
3381 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3382 rc = -EIO;
3383 else if (pSMBr->ByteCount < 40)
3384 rc = -EIO; /* bad smb */
3385 else if (pFindData) {
3386 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3387 memcpy((char *) pFindData,
3388 (char *) &pSMBr->hdr.Protocol +
3389 data_offset, sizeof(FILE_ALL_INFO));
3390 } else
3391 rc = -ENOMEM;
3392 }
3393 cifs_buf_release(pSMB);
3394 if (rc == -EAGAIN)
3395 goto QFileInfoRetry;
3396
3397 return rc;
3398}
Steve French6b8edfe2005-08-23 20:26:03 -07003399
Linus Torvalds1da177e2005-04-16 15:20:36 -07003400int
3401CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3402 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003403 FILE_ALL_INFO *pFindData,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003404 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003405 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003406{
3407/* level 263 SMB_QUERY_FILE_ALL_INFO */
3408 TRANSACTION2_QPI_REQ *pSMB = NULL;
3409 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3410 int rc = 0;
3411 int bytes_returned;
3412 int name_len;
3413 __u16 params, byte_count;
3414
Joe Perchesb6b38f72010-04-21 03:50:45 +00003415/* cFYI(1, "In QPathInfo path %s", searchName); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003416QPathInfoRetry:
3417 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3418 (void **) &pSMBr);
3419 if (rc)
3420 return rc;
3421
3422 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3423 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003424 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003425 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003426 name_len++; /* trailing null */
3427 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003428 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003429 name_len = strnlen(searchName, PATH_MAX);
3430 name_len++; /* trailing null */
3431 strncpy(pSMB->FileName, searchName, name_len);
3432 }
3433
Steve French50c2f752007-07-13 00:33:32 +00003434 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003435 pSMB->TotalDataCount = 0;
3436 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003437 /* BB find exact max SMB PDU from sess structure BB */
3438 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003439 pSMB->MaxSetupCount = 0;
3440 pSMB->Reserved = 0;
3441 pSMB->Flags = 0;
3442 pSMB->Timeout = 0;
3443 pSMB->Reserved2 = 0;
3444 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003445 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003446 pSMB->DataCount = 0;
3447 pSMB->DataOffset = 0;
3448 pSMB->SetupCount = 1;
3449 pSMB->Reserved3 = 0;
3450 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3451 byte_count = params + 1 /* pad */ ;
3452 pSMB->TotalParameterCount = cpu_to_le16(params);
3453 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00003454 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003455 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3456 else
3457 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003458 pSMB->Reserved4 = 0;
3459 pSMB->hdr.smb_buf_length += byte_count;
3460 pSMB->ByteCount = cpu_to_le16(byte_count);
3461
3462 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3463 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3464 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003465 cFYI(1, "Send error in QPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003466 } else { /* decode response */
3467 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3468
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003469 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3470 rc = -EIO;
Steve French50c2f752007-07-13 00:33:32 +00003471 else if (!legacy && (pSMBr->ByteCount < 40))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003472 rc = -EIO; /* bad smb */
Steve French790fe572007-07-07 19:25:05 +00003473 else if (legacy && (pSMBr->ByteCount < 24))
Steve French50c2f752007-07-13 00:33:32 +00003474 rc = -EIO; /* 24 or 26 expected but we do not read
3475 last field */
3476 else if (pFindData) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003477 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003478 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00003479
3480 /* On legacy responses we do not read the last field,
3481 EAsize, fortunately since it varies by subdialect and
3482 also note it differs on Set vs. Get, ie two bytes or 4
3483 bytes depending but we don't care here */
3484 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003485 size = sizeof(FILE_INFO_STANDARD);
3486 else
3487 size = sizeof(FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003488 memcpy((char *) pFindData,
3489 (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003490 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003491 } else
3492 rc = -ENOMEM;
3493 }
3494 cifs_buf_release(pSMB);
3495 if (rc == -EAGAIN)
3496 goto QPathInfoRetry;
3497
3498 return rc;
3499}
3500
3501int
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003502CIFSSMBUnixQFileInfo(const int xid, struct cifsTconInfo *tcon,
3503 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
3504{
3505 struct smb_t2_qfi_req *pSMB = NULL;
3506 struct smb_t2_qfi_rsp *pSMBr = NULL;
3507 int rc = 0;
3508 int bytes_returned;
3509 __u16 params, byte_count;
3510
3511UnixQFileInfoRetry:
3512 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3513 (void **) &pSMBr);
3514 if (rc)
3515 return rc;
3516
3517 params = 2 /* level */ + 2 /* fid */;
3518 pSMB->t2.TotalDataCount = 0;
3519 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3520 /* BB find exact max data count below from sess structure BB */
3521 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3522 pSMB->t2.MaxSetupCount = 0;
3523 pSMB->t2.Reserved = 0;
3524 pSMB->t2.Flags = 0;
3525 pSMB->t2.Timeout = 0;
3526 pSMB->t2.Reserved2 = 0;
3527 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3528 Fid) - 4);
3529 pSMB->t2.DataCount = 0;
3530 pSMB->t2.DataOffset = 0;
3531 pSMB->t2.SetupCount = 1;
3532 pSMB->t2.Reserved3 = 0;
3533 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3534 byte_count = params + 1 /* pad */ ;
3535 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3536 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3537 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3538 pSMB->Pad = 0;
3539 pSMB->Fid = netfid;
3540 pSMB->hdr.smb_buf_length += byte_count;
3541
3542 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3543 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3544 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00003545 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003546 } else { /* decode response */
3547 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3548
3549 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
Steve Frenchf19159d2010-04-21 04:12:10 +00003550 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response.\n"
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003551 "Unix Extensions can be disabled on mount "
Steve Frenchf19159d2010-04-21 04:12:10 +00003552 "by specifying the nosfu mount option.");
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003553 rc = -EIO; /* bad smb */
3554 } else {
3555 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3556 memcpy((char *) pFindData,
3557 (char *) &pSMBr->hdr.Protocol +
3558 data_offset,
3559 sizeof(FILE_UNIX_BASIC_INFO));
3560 }
3561 }
3562
3563 cifs_buf_release(pSMB);
3564 if (rc == -EAGAIN)
3565 goto UnixQFileInfoRetry;
3566
3567 return rc;
3568}
3569
3570int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003571CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3572 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00003573 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07003574 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003575{
3576/* SMB_QUERY_FILE_UNIX_BASIC */
3577 TRANSACTION2_QPI_REQ *pSMB = NULL;
3578 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3579 int rc = 0;
3580 int bytes_returned = 0;
3581 int name_len;
3582 __u16 params, byte_count;
3583
Joe Perchesb6b38f72010-04-21 03:50:45 +00003584 cFYI(1, "In QPathInfo (Unix) the path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003585UnixQPathInfoRetry:
3586 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3587 (void **) &pSMBr);
3588 if (rc)
3589 return rc;
3590
3591 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3592 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003593 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003594 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003595 name_len++; /* trailing null */
3596 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003597 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003598 name_len = strnlen(searchName, PATH_MAX);
3599 name_len++; /* trailing null */
3600 strncpy(pSMB->FileName, searchName, name_len);
3601 }
3602
Steve French50c2f752007-07-13 00:33:32 +00003603 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003604 pSMB->TotalDataCount = 0;
3605 pSMB->MaxParameterCount = cpu_to_le16(2);
3606 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00003607 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003608 pSMB->MaxSetupCount = 0;
3609 pSMB->Reserved = 0;
3610 pSMB->Flags = 0;
3611 pSMB->Timeout = 0;
3612 pSMB->Reserved2 = 0;
3613 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003614 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003615 pSMB->DataCount = 0;
3616 pSMB->DataOffset = 0;
3617 pSMB->SetupCount = 1;
3618 pSMB->Reserved3 = 0;
3619 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3620 byte_count = params + 1 /* pad */ ;
3621 pSMB->TotalParameterCount = cpu_to_le16(params);
3622 pSMB->ParameterCount = pSMB->TotalParameterCount;
3623 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3624 pSMB->Reserved4 = 0;
3625 pSMB->hdr.smb_buf_length += byte_count;
3626 pSMB->ByteCount = cpu_to_le16(byte_count);
3627
3628 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3629 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3630 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003631 cFYI(1, "Send error in QPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003632 } else { /* decode response */
3633 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3634
3635 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003636 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response.\n"
Steve French1e71f252007-09-20 15:30:07 +00003637 "Unix Extensions can be disabled on mount "
Joe Perchesb6b38f72010-04-21 03:50:45 +00003638 "by specifying the nosfu mount option.");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003639 rc = -EIO; /* bad smb */
3640 } else {
3641 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3642 memcpy((char *) pFindData,
3643 (char *) &pSMBr->hdr.Protocol +
3644 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00003645 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003646 }
3647 }
3648 cifs_buf_release(pSMB);
3649 if (rc == -EAGAIN)
3650 goto UnixQPathInfoRetry;
3651
3652 return rc;
3653}
3654
Linus Torvalds1da177e2005-04-16 15:20:36 -07003655/* xid, tcon, searchName and codepage are input parms, rest are returned */
3656int
3657CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003658 const char *searchName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003659 const struct nls_table *nls_codepage,
Steve French50c2f752007-07-13 00:33:32 +00003660 __u16 *pnetfid,
3661 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003662{
3663/* level 257 SMB_ */
3664 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3665 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00003666 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003667 int rc = 0;
3668 int bytes_returned = 0;
3669 int name_len;
3670 __u16 params, byte_count;
3671
Joe Perchesb6b38f72010-04-21 03:50:45 +00003672 cFYI(1, "In FindFirst for %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003673
3674findFirstRetry:
3675 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3676 (void **) &pSMBr);
3677 if (rc)
3678 return rc;
3679
3680 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3681 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003682 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003683 PATH_MAX, nls_codepage, remap);
3684 /* We can not add the asterik earlier in case
3685 it got remapped to 0xF03A as if it were part of the
3686 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003687 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07003688 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07003689 pSMB->FileName[name_len+1] = 0;
3690 pSMB->FileName[name_len+2] = '*';
3691 pSMB->FileName[name_len+3] = 0;
3692 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003693 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3694 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07003695 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003696 } else { /* BB add check for overrun of SMB buf BB */
3697 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003698/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00003699 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003700 free buffer exit; BB */
3701 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07003702 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07003703 pSMB->FileName[name_len+1] = '*';
3704 pSMB->FileName[name_len+2] = 0;
3705 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003706 }
3707
3708 params = 12 + name_len /* includes null */ ;
3709 pSMB->TotalDataCount = 0; /* no EAs */
3710 pSMB->MaxParameterCount = cpu_to_le16(10);
3711 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3712 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3713 pSMB->MaxSetupCount = 0;
3714 pSMB->Reserved = 0;
3715 pSMB->Flags = 0;
3716 pSMB->Timeout = 0;
3717 pSMB->Reserved2 = 0;
3718 byte_count = params + 1 /* pad */ ;
3719 pSMB->TotalParameterCount = cpu_to_le16(params);
3720 pSMB->ParameterCount = pSMB->TotalParameterCount;
3721 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00003722 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3723 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003724 pSMB->DataCount = 0;
3725 pSMB->DataOffset = 0;
3726 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3727 pSMB->Reserved3 = 0;
3728 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3729 pSMB->SearchAttributes =
3730 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3731 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00003732 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3733 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
Linus Torvalds1da177e2005-04-16 15:20:36 -07003734 CIFS_SEARCH_RETURN_RESUME);
3735 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3736
3737 /* BB what should we set StorageType to? Does it matter? BB */
3738 pSMB->SearchStorageType = 0;
3739 pSMB->hdr.smb_buf_length += byte_count;
3740 pSMB->ByteCount = cpu_to_le16(byte_count);
3741
3742 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3743 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003744 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003745
Steve French88274812006-03-09 22:21:45 +00003746 if (rc) {/* BB add logic to retry regular search if Unix search
3747 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003748 /* BB Add code to handle unsupported level rc */
Joe Perchesb6b38f72010-04-21 03:50:45 +00003749 cFYI(1, "Error in FindFirst = %d", rc);
Steve French1982c342005-08-17 12:38:22 -07003750
Steve French88274812006-03-09 22:21:45 +00003751 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003752
3753 /* BB eventually could optimize out free and realloc of buf */
3754 /* for this case */
3755 if (rc == -EAGAIN)
3756 goto findFirstRetry;
3757 } else { /* decode response */
3758 /* BB remember to free buffer if error BB */
3759 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003760 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00003761 unsigned int lnoff;
3762
Linus Torvalds1da177e2005-04-16 15:20:36 -07003763 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00003764 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003765 else
Steve French4b18f2a2008-04-29 00:06:05 +00003766 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003767
3768 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003769 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00003770 psrch_inf->srch_entries_start =
3771 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003772 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003773 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3774 le16_to_cpu(pSMBr->t2.ParameterOffset));
3775
Steve French790fe572007-07-07 19:25:05 +00003776 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00003777 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003778 else
Steve French4b18f2a2008-04-29 00:06:05 +00003779 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003780
Steve French50c2f752007-07-13 00:33:32 +00003781 psrch_inf->entries_in_buffer =
3782 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00003783 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003784 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00003785 lnoff = le16_to_cpu(parms->LastNameOffset);
3786 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3787 lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003788 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00003789 psrch_inf->last_entry = NULL;
3790 return rc;
3791 }
3792
Steve French0752f152008-10-07 20:03:33 +00003793 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00003794 lnoff;
3795
Linus Torvalds1da177e2005-04-16 15:20:36 -07003796 *pnetfid = parms->SearchHandle;
3797 } else {
3798 cifs_buf_release(pSMB);
3799 }
3800 }
3801
3802 return rc;
3803}
3804
3805int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003806 __u16 searchHandle, struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003807{
3808 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3809 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00003810 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003811 char *response_data;
3812 int rc = 0;
3813 int bytes_returned, name_len;
3814 __u16 params, byte_count;
3815
Joe Perchesb6b38f72010-04-21 03:50:45 +00003816 cFYI(1, "In FindNext");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003817
Steve French4b18f2a2008-04-29 00:06:05 +00003818 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003819 return -ENOENT;
3820
3821 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3822 (void **) &pSMBr);
3823 if (rc)
3824 return rc;
3825
Steve French50c2f752007-07-13 00:33:32 +00003826 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003827 byte_count = 0;
3828 pSMB->TotalDataCount = 0; /* no EAs */
3829 pSMB->MaxParameterCount = cpu_to_le16(8);
3830 pSMB->MaxDataCount =
Steve French50c2f752007-07-13 00:33:32 +00003831 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
3832 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003833 pSMB->MaxSetupCount = 0;
3834 pSMB->Reserved = 0;
3835 pSMB->Flags = 0;
3836 pSMB->Timeout = 0;
3837 pSMB->Reserved2 = 0;
3838 pSMB->ParameterOffset = cpu_to_le16(
3839 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3840 pSMB->DataCount = 0;
3841 pSMB->DataOffset = 0;
3842 pSMB->SetupCount = 1;
3843 pSMB->Reserved3 = 0;
3844 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3845 pSMB->SearchHandle = searchHandle; /* always kept as le */
3846 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00003847 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003848 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3849 pSMB->ResumeKey = psrch_inf->resume_key;
3850 pSMB->SearchFlags =
3851 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3852
3853 name_len = psrch_inf->resume_name_len;
3854 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00003855 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003856 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3857 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07003858 /* 14 byte parm len above enough for 2 byte null terminator */
3859 pSMB->ResumeFileName[name_len] = 0;
3860 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003861 } else {
3862 rc = -EINVAL;
3863 goto FNext2_err_exit;
3864 }
3865 byte_count = params + 1 /* pad */ ;
3866 pSMB->TotalParameterCount = cpu_to_le16(params);
3867 pSMB->ParameterCount = pSMB->TotalParameterCount;
3868 pSMB->hdr.smb_buf_length += byte_count;
3869 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00003870
Linus Torvalds1da177e2005-04-16 15:20:36 -07003871 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3872 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003873 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003874 if (rc) {
3875 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00003876 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07003877 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00003878 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003879 } else
Joe Perchesb6b38f72010-04-21 03:50:45 +00003880 cFYI(1, "FindNext returned = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003881 } else { /* decode response */
3882 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00003883
Steve French790fe572007-07-07 19:25:05 +00003884 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00003885 unsigned int lnoff;
3886
Linus Torvalds1da177e2005-04-16 15:20:36 -07003887 /* BB fixme add lock for file (srch_info) struct here */
3888 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00003889 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003890 else
Steve French4b18f2a2008-04-29 00:06:05 +00003891 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003892 response_data = (char *) &pSMBr->hdr.Protocol +
3893 le16_to_cpu(pSMBr->t2.ParameterOffset);
3894 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3895 response_data = (char *)&pSMBr->hdr.Protocol +
3896 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00003897 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00003898 cifs_small_buf_release(
3899 psrch_inf->ntwrk_buf_start);
3900 else
3901 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003902 psrch_inf->srch_entries_start = response_data;
3903 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003904 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00003905 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00003906 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003907 else
Steve French4b18f2a2008-04-29 00:06:05 +00003908 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00003909 psrch_inf->entries_in_buffer =
3910 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003911 psrch_inf->index_of_last_entry +=
3912 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00003913 lnoff = le16_to_cpu(parms->LastNameOffset);
3914 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3915 lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003916 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00003917 psrch_inf->last_entry = NULL;
3918 return rc;
3919 } else
3920 psrch_inf->last_entry =
3921 psrch_inf->srch_entries_start + lnoff;
3922
Joe Perchesb6b38f72010-04-21 03:50:45 +00003923/* cFYI(1, "fnxt2 entries in buf %d index_of_last %d",
3924 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003925
3926 /* BB fixme add unlock here */
3927 }
3928
3929 }
3930
3931 /* BB On error, should we leave previous search buf (and count and
3932 last entry fields) intact or free the previous one? */
3933
3934 /* Note: On -EAGAIN error only caller can retry on handle based calls
3935 since file handle passed in no longer valid */
3936FNext2_err_exit:
3937 if (rc != 0)
3938 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003939 return rc;
3940}
3941
3942int
Steve French50c2f752007-07-13 00:33:32 +00003943CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
3944 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003945{
3946 int rc = 0;
3947 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003948
Joe Perchesb6b38f72010-04-21 03:50:45 +00003949 cFYI(1, "In CIFSSMBFindClose");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003950 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3951
3952 /* no sense returning error if session restarted
3953 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00003954 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003955 return 0;
3956 if (rc)
3957 return rc;
3958
Linus Torvalds1da177e2005-04-16 15:20:36 -07003959 pSMB->FileID = searchHandle;
3960 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00003961 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003962 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003963 cERROR(1, "Send error in FindClose = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00003964
Steve Frencha4544342005-08-24 13:59:35 -07003965 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003966
3967 /* Since session is dead, search handle closed on server already */
3968 if (rc == -EAGAIN)
3969 rc = 0;
3970
3971 return rc;
3972}
3973
Linus Torvalds1da177e2005-04-16 15:20:36 -07003974int
3975CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003976 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003977 __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00003978 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003979{
3980 int rc = 0;
3981 TRANSACTION2_QPI_REQ *pSMB = NULL;
3982 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3983 int name_len, bytes_returned;
3984 __u16 params, byte_count;
3985
Joe Perchesb6b38f72010-04-21 03:50:45 +00003986 cFYI(1, "In GetSrvInodeNum for %s", searchName);
Steve French790fe572007-07-07 19:25:05 +00003987 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00003988 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003989
3990GetInodeNumberRetry:
3991 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003992 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003993 if (rc)
3994 return rc;
3995
Linus Torvalds1da177e2005-04-16 15:20:36 -07003996 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3997 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003998 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French50c2f752007-07-13 00:33:32 +00003999 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004000 name_len++; /* trailing null */
4001 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004002 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004003 name_len = strnlen(searchName, PATH_MAX);
4004 name_len++; /* trailing null */
4005 strncpy(pSMB->FileName, searchName, name_len);
4006 }
4007
4008 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4009 pSMB->TotalDataCount = 0;
4010 pSMB->MaxParameterCount = cpu_to_le16(2);
4011 /* BB find exact max data count below from sess structure BB */
4012 pSMB->MaxDataCount = cpu_to_le16(4000);
4013 pSMB->MaxSetupCount = 0;
4014 pSMB->Reserved = 0;
4015 pSMB->Flags = 0;
4016 pSMB->Timeout = 0;
4017 pSMB->Reserved2 = 0;
4018 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004019 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004020 pSMB->DataCount = 0;
4021 pSMB->DataOffset = 0;
4022 pSMB->SetupCount = 1;
4023 pSMB->Reserved3 = 0;
4024 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4025 byte_count = params + 1 /* pad */ ;
4026 pSMB->TotalParameterCount = cpu_to_le16(params);
4027 pSMB->ParameterCount = pSMB->TotalParameterCount;
4028 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4029 pSMB->Reserved4 = 0;
4030 pSMB->hdr.smb_buf_length += byte_count;
4031 pSMB->ByteCount = cpu_to_le16(byte_count);
4032
4033 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4034 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4035 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004036 cFYI(1, "error %d in QueryInternalInfo", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004037 } else {
4038 /* decode response */
4039 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4040 if (rc || (pSMBr->ByteCount < 2))
4041 /* BB also check enough total bytes returned */
4042 /* If rc should we check for EOPNOSUPP and
4043 disable the srvino flag? or in caller? */
4044 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00004045 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004046 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4047 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00004048 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004049 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00004050 if (count < 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004051 cFYI(1, "Illegal size ret in QryIntrnlInf");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004052 rc = -EIO;
4053 goto GetInodeNumOut;
4054 }
4055 pfinfo = (struct file_internal_info *)
4056 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00004057 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004058 }
4059 }
4060GetInodeNumOut:
4061 cifs_buf_release(pSMB);
4062 if (rc == -EAGAIN)
4063 goto GetInodeNumberRetry;
4064 return rc;
4065}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004066
Igor Mammedovfec45852008-05-16 13:06:30 +04004067/* parses DFS refferal V3 structure
4068 * caller is responsible for freeing target_nodes
4069 * returns:
4070 * on success - 0
4071 * on failure - errno
4072 */
4073static int
Steve Frencha1fe78f2008-05-16 18:48:38 +00004074parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
Igor Mammedovfec45852008-05-16 13:06:30 +04004075 unsigned int *num_of_nodes,
4076 struct dfs_info3_param **target_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004077 const struct nls_table *nls_codepage, int remap,
4078 const char *searchName)
Igor Mammedovfec45852008-05-16 13:06:30 +04004079{
4080 int i, rc = 0;
4081 char *data_end;
4082 bool is_unicode;
4083 struct dfs_referral_level_3 *ref;
4084
Harvey Harrison5ca33c62008-07-23 17:45:58 -07004085 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4086 is_unicode = true;
4087 else
4088 is_unicode = false;
Igor Mammedovfec45852008-05-16 13:06:30 +04004089 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
4090
4091 if (*num_of_nodes < 1) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004092 cERROR(1, "num_referrals: must be at least > 0,"
4093 "but we get num_referrals = %d\n", *num_of_nodes);
Igor Mammedovfec45852008-05-16 13:06:30 +04004094 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004095 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004096 }
4097
4098 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
Al Viro1d92cfd2008-06-02 10:59:02 +01004099 if (ref->VersionNumber != cpu_to_le16(3)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004100 cERROR(1, "Referrals of V%d version are not supported,"
4101 "should be V3", le16_to_cpu(ref->VersionNumber));
Igor Mammedovfec45852008-05-16 13:06:30 +04004102 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004103 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004104 }
4105
4106 /* get the upper boundary of the resp buffer */
4107 data_end = (char *)(&(pSMBr->PathConsumed)) +
4108 le16_to_cpu(pSMBr->t2.DataCount);
4109
Steve Frenchf19159d2010-04-21 04:12:10 +00004110 cFYI(1, "num_referrals: %d dfs flags: 0x%x ...\n",
Igor Mammedovfec45852008-05-16 13:06:30 +04004111 *num_of_nodes,
Joe Perchesb6b38f72010-04-21 03:50:45 +00004112 le32_to_cpu(pSMBr->DFSFlags));
Igor Mammedovfec45852008-05-16 13:06:30 +04004113
4114 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
4115 *num_of_nodes, GFP_KERNEL);
4116 if (*target_nodes == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004117 cERROR(1, "Failed to allocate buffer for target_nodes\n");
Igor Mammedovfec45852008-05-16 13:06:30 +04004118 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004119 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004120 }
4121
Daniel Mack3ad2f3f2010-02-03 08:01:28 +08004122 /* collect necessary data from referrals */
Igor Mammedovfec45852008-05-16 13:06:30 +04004123 for (i = 0; i < *num_of_nodes; i++) {
4124 char *temp;
4125 int max_len;
4126 struct dfs_info3_param *node = (*target_nodes)+i;
4127
Steve French0e0d2cf2009-05-01 05:27:32 +00004128 node->flags = le32_to_cpu(pSMBr->DFSFlags);
Igor Mammedov2c556082008-10-23 13:58:42 +04004129 if (is_unicode) {
Jeff Layton331c3132008-12-17 06:31:53 -05004130 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4131 GFP_KERNEL);
Steve French2920ee22009-08-31 15:27:26 +00004132 if (tmp == NULL) {
4133 rc = -ENOMEM;
4134 goto parse_DFS_referrals_exit;
4135 }
Igor Mammedov2c556082008-10-23 13:58:42 +04004136 cifsConvertToUCS((__le16 *) tmp, searchName,
4137 PATH_MAX, nls_codepage, remap);
Jeff Layton69f801f2009-04-30 06:46:32 -04004138 node->path_consumed = cifs_ucs2_bytes(tmp,
4139 le16_to_cpu(pSMBr->PathConsumed),
Igor Mammedov2c556082008-10-23 13:58:42 +04004140 nls_codepage);
4141 kfree(tmp);
4142 } else
4143 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4144
Igor Mammedovfec45852008-05-16 13:06:30 +04004145 node->server_type = le16_to_cpu(ref->ServerType);
4146 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4147
4148 /* copy DfsPath */
4149 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4150 max_len = data_end - temp;
Steve Frenchd185cda2009-04-30 17:45:10 +00004151 node->path_name = cifs_strndup_from_ucs(temp, max_len,
4152 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004153 if (!node->path_name) {
4154 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004155 goto parse_DFS_referrals_exit;
Jeff Layton066ce682009-04-30 07:16:14 -04004156 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004157
4158 /* copy link target UNC */
4159 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4160 max_len = data_end - temp;
Steve Frenchd185cda2009-04-30 17:45:10 +00004161 node->node_name = cifs_strndup_from_ucs(temp, max_len,
4162 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004163 if (!node->node_name)
4164 rc = -ENOMEM;
Igor Mammedovfec45852008-05-16 13:06:30 +04004165 }
4166
Steve Frencha1fe78f2008-05-16 18:48:38 +00004167parse_DFS_referrals_exit:
Igor Mammedovfec45852008-05-16 13:06:30 +04004168 if (rc) {
4169 free_dfs_info_array(*target_nodes, *num_of_nodes);
4170 *target_nodes = NULL;
4171 *num_of_nodes = 0;
4172 }
4173 return rc;
4174}
4175
Linus Torvalds1da177e2005-04-16 15:20:36 -07004176int
4177CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
4178 const unsigned char *searchName,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004179 struct dfs_info3_param **target_nodes,
4180 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004181 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004182{
4183/* TRANS2_GET_DFS_REFERRAL */
4184 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4185 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004186 int rc = 0;
4187 int bytes_returned;
4188 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004189 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004190 *num_of_nodes = 0;
4191 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004192
Joe Perchesb6b38f72010-04-21 03:50:45 +00004193 cFYI(1, "In GetDFSRefer the path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004194 if (ses == NULL)
4195 return -ENODEV;
4196getDFSRetry:
4197 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4198 (void **) &pSMBr);
4199 if (rc)
4200 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004201
4202 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004203 but should never be null here anyway */
4204 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004205 pSMB->hdr.Tid = ses->ipc_tid;
4206 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004207 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004208 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004209 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004210 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004211
4212 if (ses->capabilities & CAP_UNICODE) {
4213 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4214 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004215 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07004216 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004217 name_len++; /* trailing null */
4218 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004219 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004220 name_len = strnlen(searchName, PATH_MAX);
4221 name_len++; /* trailing null */
4222 strncpy(pSMB->RequestFileName, searchName, name_len);
4223 }
4224
Steve French790fe572007-07-07 19:25:05 +00004225 if (ses->server) {
4226 if (ses->server->secMode &
Steve French1a4e15a2006-10-12 21:33:51 +00004227 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4228 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4229 }
4230
Steve French50c2f752007-07-13 00:33:32 +00004231 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004232
Linus Torvalds1da177e2005-04-16 15:20:36 -07004233 params = 2 /* level */ + name_len /*includes null */ ;
4234 pSMB->TotalDataCount = 0;
4235 pSMB->DataCount = 0;
4236 pSMB->DataOffset = 0;
4237 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004238 /* BB find exact max SMB PDU from sess structure BB */
4239 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004240 pSMB->MaxSetupCount = 0;
4241 pSMB->Reserved = 0;
4242 pSMB->Flags = 0;
4243 pSMB->Timeout = 0;
4244 pSMB->Reserved2 = 0;
4245 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004246 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004247 pSMB->SetupCount = 1;
4248 pSMB->Reserved3 = 0;
4249 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4250 byte_count = params + 3 /* pad */ ;
4251 pSMB->ParameterCount = cpu_to_le16(params);
4252 pSMB->TotalParameterCount = pSMB->ParameterCount;
4253 pSMB->MaxReferralLevel = cpu_to_le16(3);
4254 pSMB->hdr.smb_buf_length += byte_count;
4255 pSMB->ByteCount = cpu_to_le16(byte_count);
4256
4257 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4258 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4259 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004260 cFYI(1, "Send error in GetDFSRefer = %d", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004261 goto GetDFSRefExit;
4262 }
4263 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004264
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004265 /* BB Also check if enough total bytes returned? */
Igor Mammedovfec45852008-05-16 13:06:30 +04004266 if (rc || (pSMBr->ByteCount < 17)) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004267 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004268 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004269 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004270
Joe Perchesb6b38f72010-04-21 03:50:45 +00004271 cFYI(1, "Decoding GetDFSRefer response BCC: %d Offset %d",
Igor Mammedovfec45852008-05-16 13:06:30 +04004272 pSMBr->ByteCount,
Joe Perchesb6b38f72010-04-21 03:50:45 +00004273 le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04004274
4275 /* parse returned result into more usable form */
Steve Frencha1fe78f2008-05-16 18:48:38 +00004276 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004277 target_nodes, nls_codepage, remap,
4278 searchName);
Igor Mammedovfec45852008-05-16 13:06:30 +04004279
Linus Torvalds1da177e2005-04-16 15:20:36 -07004280GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004281 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004282
4283 if (rc == -EAGAIN)
4284 goto getDFSRetry;
4285
4286 return rc;
4287}
4288
Steve French20962432005-09-21 22:05:57 -07004289/* Query File System Info such as free space to old servers such as Win 9x */
4290int
4291SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4292{
4293/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4294 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4295 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4296 FILE_SYSTEM_ALLOC_INFO *response_data;
4297 int rc = 0;
4298 int bytes_returned = 0;
4299 __u16 params, byte_count;
4300
Joe Perchesb6b38f72010-04-21 03:50:45 +00004301 cFYI(1, "OldQFSInfo");
Steve French20962432005-09-21 22:05:57 -07004302oldQFSInfoRetry:
4303 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4304 (void **) &pSMBr);
4305 if (rc)
4306 return rc;
Steve French20962432005-09-21 22:05:57 -07004307
4308 params = 2; /* level */
4309 pSMB->TotalDataCount = 0;
4310 pSMB->MaxParameterCount = cpu_to_le16(2);
4311 pSMB->MaxDataCount = cpu_to_le16(1000);
4312 pSMB->MaxSetupCount = 0;
4313 pSMB->Reserved = 0;
4314 pSMB->Flags = 0;
4315 pSMB->Timeout = 0;
4316 pSMB->Reserved2 = 0;
4317 byte_count = params + 1 /* pad */ ;
4318 pSMB->TotalParameterCount = cpu_to_le16(params);
4319 pSMB->ParameterCount = pSMB->TotalParameterCount;
4320 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4321 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4322 pSMB->DataCount = 0;
4323 pSMB->DataOffset = 0;
4324 pSMB->SetupCount = 1;
4325 pSMB->Reserved3 = 0;
4326 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4327 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
4328 pSMB->hdr.smb_buf_length += byte_count;
4329 pSMB->ByteCount = cpu_to_le16(byte_count);
4330
4331 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4332 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4333 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004334 cFYI(1, "Send error in QFSInfo = %d", rc);
Steve French20962432005-09-21 22:05:57 -07004335 } else { /* decode response */
4336 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4337
4338 if (rc || (pSMBr->ByteCount < 18))
4339 rc = -EIO; /* bad smb */
4340 else {
4341 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004342 cFYI(1, "qfsinf resp BCC: %d Offset %d",
4343 pSMBr->ByteCount, data_offset);
Steve French20962432005-09-21 22:05:57 -07004344
Steve French50c2f752007-07-13 00:33:32 +00004345 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004346 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4347 FSData->f_bsize =
4348 le16_to_cpu(response_data->BytesPerSector) *
4349 le32_to_cpu(response_data->
4350 SectorsPerAllocationUnit);
4351 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004352 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004353 FSData->f_bfree = FSData->f_bavail =
4354 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004355 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
4356 (unsigned long long)FSData->f_blocks,
4357 (unsigned long long)FSData->f_bfree,
4358 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07004359 }
4360 }
4361 cifs_buf_release(pSMB);
4362
4363 if (rc == -EAGAIN)
4364 goto oldQFSInfoRetry;
4365
4366 return rc;
4367}
4368
Linus Torvalds1da177e2005-04-16 15:20:36 -07004369int
Steve French737b7582005-04-28 22:41:06 -07004370CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004371{
4372/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4373 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4374 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4375 FILE_SYSTEM_INFO *response_data;
4376 int rc = 0;
4377 int bytes_returned = 0;
4378 __u16 params, byte_count;
4379
Joe Perchesb6b38f72010-04-21 03:50:45 +00004380 cFYI(1, "In QFSInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004381QFSInfoRetry:
4382 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4383 (void **) &pSMBr);
4384 if (rc)
4385 return rc;
4386
4387 params = 2; /* level */
4388 pSMB->TotalDataCount = 0;
4389 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004390 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004391 pSMB->MaxSetupCount = 0;
4392 pSMB->Reserved = 0;
4393 pSMB->Flags = 0;
4394 pSMB->Timeout = 0;
4395 pSMB->Reserved2 = 0;
4396 byte_count = params + 1 /* pad */ ;
4397 pSMB->TotalParameterCount = cpu_to_le16(params);
4398 pSMB->ParameterCount = pSMB->TotalParameterCount;
4399 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004400 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004401 pSMB->DataCount = 0;
4402 pSMB->DataOffset = 0;
4403 pSMB->SetupCount = 1;
4404 pSMB->Reserved3 = 0;
4405 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4406 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
4407 pSMB->hdr.smb_buf_length += byte_count;
4408 pSMB->ByteCount = cpu_to_le16(byte_count);
4409
4410 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4411 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4412 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004413 cFYI(1, "Send error in QFSInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004414 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00004415 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004416
Steve French20962432005-09-21 22:05:57 -07004417 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004418 rc = -EIO; /* bad smb */
4419 else {
4420 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004421
4422 response_data =
4423 (FILE_SYSTEM_INFO
4424 *) (((char *) &pSMBr->hdr.Protocol) +
4425 data_offset);
4426 FSData->f_bsize =
4427 le32_to_cpu(response_data->BytesPerSector) *
4428 le32_to_cpu(response_data->
4429 SectorsPerAllocationUnit);
4430 FSData->f_blocks =
4431 le64_to_cpu(response_data->TotalAllocationUnits);
4432 FSData->f_bfree = FSData->f_bavail =
4433 le64_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004434 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
4435 (unsigned long long)FSData->f_blocks,
4436 (unsigned long long)FSData->f_bfree,
4437 FSData->f_bsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004438 }
4439 }
4440 cifs_buf_release(pSMB);
4441
4442 if (rc == -EAGAIN)
4443 goto QFSInfoRetry;
4444
4445 return rc;
4446}
4447
4448int
Steve French737b7582005-04-28 22:41:06 -07004449CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004450{
4451/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4452 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4453 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4454 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4455 int rc = 0;
4456 int bytes_returned = 0;
4457 __u16 params, byte_count;
4458
Joe Perchesb6b38f72010-04-21 03:50:45 +00004459 cFYI(1, "In QFSAttributeInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004460QFSAttributeRetry:
4461 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4462 (void **) &pSMBr);
4463 if (rc)
4464 return rc;
4465
4466 params = 2; /* level */
4467 pSMB->TotalDataCount = 0;
4468 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004469 /* BB find exact max SMB PDU from sess structure BB */
4470 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004471 pSMB->MaxSetupCount = 0;
4472 pSMB->Reserved = 0;
4473 pSMB->Flags = 0;
4474 pSMB->Timeout = 0;
4475 pSMB->Reserved2 = 0;
4476 byte_count = params + 1 /* pad */ ;
4477 pSMB->TotalParameterCount = cpu_to_le16(params);
4478 pSMB->ParameterCount = pSMB->TotalParameterCount;
4479 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004480 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004481 pSMB->DataCount = 0;
4482 pSMB->DataOffset = 0;
4483 pSMB->SetupCount = 1;
4484 pSMB->Reserved3 = 0;
4485 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4486 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4487 pSMB->hdr.smb_buf_length += byte_count;
4488 pSMB->ByteCount = cpu_to_le16(byte_count);
4489
4490 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4491 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4492 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004493 cERROR(1, "Send error in QFSAttributeInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004494 } else { /* decode response */
4495 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4496
Steve French50c2f752007-07-13 00:33:32 +00004497 if (rc || (pSMBr->ByteCount < 13)) {
4498 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004499 rc = -EIO; /* bad smb */
4500 } else {
4501 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4502 response_data =
4503 (FILE_SYSTEM_ATTRIBUTE_INFO
4504 *) (((char *) &pSMBr->hdr.Protocol) +
4505 data_offset);
4506 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004507 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004508 }
4509 }
4510 cifs_buf_release(pSMB);
4511
4512 if (rc == -EAGAIN)
4513 goto QFSAttributeRetry;
4514
4515 return rc;
4516}
4517
4518int
Steve French737b7582005-04-28 22:41:06 -07004519CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004520{
4521/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4522 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4523 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4524 FILE_SYSTEM_DEVICE_INFO *response_data;
4525 int rc = 0;
4526 int bytes_returned = 0;
4527 __u16 params, byte_count;
4528
Joe Perchesb6b38f72010-04-21 03:50:45 +00004529 cFYI(1, "In QFSDeviceInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004530QFSDeviceRetry:
4531 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4532 (void **) &pSMBr);
4533 if (rc)
4534 return rc;
4535
4536 params = 2; /* level */
4537 pSMB->TotalDataCount = 0;
4538 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004539 /* BB find exact max SMB PDU from sess structure BB */
4540 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004541 pSMB->MaxSetupCount = 0;
4542 pSMB->Reserved = 0;
4543 pSMB->Flags = 0;
4544 pSMB->Timeout = 0;
4545 pSMB->Reserved2 = 0;
4546 byte_count = params + 1 /* pad */ ;
4547 pSMB->TotalParameterCount = cpu_to_le16(params);
4548 pSMB->ParameterCount = pSMB->TotalParameterCount;
4549 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004550 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004551
4552 pSMB->DataCount = 0;
4553 pSMB->DataOffset = 0;
4554 pSMB->SetupCount = 1;
4555 pSMB->Reserved3 = 0;
4556 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4557 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4558 pSMB->hdr.smb_buf_length += byte_count;
4559 pSMB->ByteCount = cpu_to_le16(byte_count);
4560
4561 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4562 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4563 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004564 cFYI(1, "Send error in QFSDeviceInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004565 } else { /* decode response */
4566 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4567
Steve French630f3f0c2007-10-25 21:17:17 +00004568 if (rc || (pSMBr->ByteCount < sizeof(FILE_SYSTEM_DEVICE_INFO)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004569 rc = -EIO; /* bad smb */
4570 else {
4571 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4572 response_data =
Steve French737b7582005-04-28 22:41:06 -07004573 (FILE_SYSTEM_DEVICE_INFO *)
4574 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004575 data_offset);
4576 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004577 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004578 }
4579 }
4580 cifs_buf_release(pSMB);
4581
4582 if (rc == -EAGAIN)
4583 goto QFSDeviceRetry;
4584
4585 return rc;
4586}
4587
4588int
Steve French737b7582005-04-28 22:41:06 -07004589CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004590{
4591/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4592 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4593 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4594 FILE_SYSTEM_UNIX_INFO *response_data;
4595 int rc = 0;
4596 int bytes_returned = 0;
4597 __u16 params, byte_count;
4598
Joe Perchesb6b38f72010-04-21 03:50:45 +00004599 cFYI(1, "In QFSUnixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004600QFSUnixRetry:
Jeff Laytonf5695992010-09-29 15:27:08 -04004601 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
4602 (void **) &pSMB, (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004603 if (rc)
4604 return rc;
4605
4606 params = 2; /* level */
4607 pSMB->TotalDataCount = 0;
4608 pSMB->DataCount = 0;
4609 pSMB->DataOffset = 0;
4610 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004611 /* BB find exact max SMB PDU from sess structure BB */
4612 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004613 pSMB->MaxSetupCount = 0;
4614 pSMB->Reserved = 0;
4615 pSMB->Flags = 0;
4616 pSMB->Timeout = 0;
4617 pSMB->Reserved2 = 0;
4618 byte_count = params + 1 /* pad */ ;
4619 pSMB->ParameterCount = cpu_to_le16(params);
4620 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004621 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4622 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004623 pSMB->SetupCount = 1;
4624 pSMB->Reserved3 = 0;
4625 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4626 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4627 pSMB->hdr.smb_buf_length += byte_count;
4628 pSMB->ByteCount = cpu_to_le16(byte_count);
4629
4630 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4631 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4632 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004633 cERROR(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004634 } else { /* decode response */
4635 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4636
4637 if (rc || (pSMBr->ByteCount < 13)) {
4638 rc = -EIO; /* bad smb */
4639 } else {
4640 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4641 response_data =
4642 (FILE_SYSTEM_UNIX_INFO
4643 *) (((char *) &pSMBr->hdr.Protocol) +
4644 data_offset);
4645 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004646 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004647 }
4648 }
4649 cifs_buf_release(pSMB);
4650
4651 if (rc == -EAGAIN)
4652 goto QFSUnixRetry;
4653
4654
4655 return rc;
4656}
4657
Jeremy Allisonac670552005-06-22 17:26:35 -07004658int
Steve French45abc6e2005-06-23 13:42:03 -05004659CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07004660{
4661/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4662 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4663 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4664 int rc = 0;
4665 int bytes_returned = 0;
4666 __u16 params, param_offset, offset, byte_count;
4667
Joe Perchesb6b38f72010-04-21 03:50:45 +00004668 cFYI(1, "In SETFSUnixInfo");
Jeremy Allisonac670552005-06-22 17:26:35 -07004669SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00004670 /* BB switch to small buf init to save memory */
Jeff Laytonf5695992010-09-29 15:27:08 -04004671 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
4672 (void **) &pSMB, (void **) &pSMBr);
Jeremy Allisonac670552005-06-22 17:26:35 -07004673 if (rc)
4674 return rc;
4675
4676 params = 4; /* 2 bytes zero followed by info level. */
4677 pSMB->MaxSetupCount = 0;
4678 pSMB->Reserved = 0;
4679 pSMB->Flags = 0;
4680 pSMB->Timeout = 0;
4681 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00004682 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4683 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07004684 offset = param_offset + params;
4685
4686 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00004687 /* BB find exact max SMB PDU from sess structure BB */
4688 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07004689 pSMB->SetupCount = 1;
4690 pSMB->Reserved3 = 0;
4691 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4692 byte_count = 1 /* pad */ + params + 12;
4693
4694 pSMB->DataCount = cpu_to_le16(12);
4695 pSMB->ParameterCount = cpu_to_le16(params);
4696 pSMB->TotalDataCount = pSMB->DataCount;
4697 pSMB->TotalParameterCount = pSMB->ParameterCount;
4698 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4699 pSMB->DataOffset = cpu_to_le16(offset);
4700
4701 /* Params. */
4702 pSMB->FileNum = 0;
4703 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4704
4705 /* Data. */
4706 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4707 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4708 pSMB->ClientUnixCap = cpu_to_le64(cap);
4709
4710 pSMB->hdr.smb_buf_length += byte_count;
4711 pSMB->ByteCount = cpu_to_le16(byte_count);
4712
4713 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4714 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4715 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004716 cERROR(1, "Send error in SETFSUnixInfo = %d", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07004717 } else { /* decode response */
4718 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00004719 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07004720 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07004721 }
4722 cifs_buf_release(pSMB);
4723
4724 if (rc == -EAGAIN)
4725 goto SETFSUnixRetry;
4726
4727 return rc;
4728}
4729
4730
Linus Torvalds1da177e2005-04-16 15:20:36 -07004731
4732int
4733CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004734 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004735{
4736/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4737 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4738 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4739 FILE_SYSTEM_POSIX_INFO *response_data;
4740 int rc = 0;
4741 int bytes_returned = 0;
4742 __u16 params, byte_count;
4743
Joe Perchesb6b38f72010-04-21 03:50:45 +00004744 cFYI(1, "In QFSPosixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004745QFSPosixRetry:
4746 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4747 (void **) &pSMBr);
4748 if (rc)
4749 return rc;
4750
4751 params = 2; /* level */
4752 pSMB->TotalDataCount = 0;
4753 pSMB->DataCount = 0;
4754 pSMB->DataOffset = 0;
4755 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004756 /* BB find exact max SMB PDU from sess structure BB */
4757 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004758 pSMB->MaxSetupCount = 0;
4759 pSMB->Reserved = 0;
4760 pSMB->Flags = 0;
4761 pSMB->Timeout = 0;
4762 pSMB->Reserved2 = 0;
4763 byte_count = params + 1 /* pad */ ;
4764 pSMB->ParameterCount = cpu_to_le16(params);
4765 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004766 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4767 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004768 pSMB->SetupCount = 1;
4769 pSMB->Reserved3 = 0;
4770 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4771 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4772 pSMB->hdr.smb_buf_length += byte_count;
4773 pSMB->ByteCount = cpu_to_le16(byte_count);
4774
4775 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4776 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4777 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004778 cFYI(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004779 } else { /* decode response */
4780 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4781
4782 if (rc || (pSMBr->ByteCount < 13)) {
4783 rc = -EIO; /* bad smb */
4784 } else {
4785 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4786 response_data =
4787 (FILE_SYSTEM_POSIX_INFO
4788 *) (((char *) &pSMBr->hdr.Protocol) +
4789 data_offset);
4790 FSData->f_bsize =
4791 le32_to_cpu(response_data->BlockSize);
4792 FSData->f_blocks =
4793 le64_to_cpu(response_data->TotalBlocks);
4794 FSData->f_bfree =
4795 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00004796 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004797 FSData->f_bavail = FSData->f_bfree;
4798 } else {
4799 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00004800 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004801 }
Steve French790fe572007-07-07 19:25:05 +00004802 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004803 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00004804 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00004805 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004806 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00004807 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004808 }
4809 }
4810 cifs_buf_release(pSMB);
4811
4812 if (rc == -EAGAIN)
4813 goto QFSPosixRetry;
4814
4815 return rc;
4816}
4817
4818
Steve French50c2f752007-07-13 00:33:32 +00004819/* We can not use write of zero bytes trick to
4820 set file size due to need for large file support. Also note that
4821 this SetPathInfo is preferred to SetFileInfo based method in next
Linus Torvalds1da177e2005-04-16 15:20:36 -07004822 routine which is only needed to work around a sharing violation bug
4823 in Samba which this routine can run into */
4824
4825int
4826CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French4b18f2a2008-04-29 00:06:05 +00004827 __u64 size, bool SetAllocation,
Steve French737b7582005-04-28 22:41:06 -07004828 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004829{
4830 struct smb_com_transaction2_spi_req *pSMB = NULL;
4831 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4832 struct file_end_of_file_info *parm_data;
4833 int name_len;
4834 int rc = 0;
4835 int bytes_returned = 0;
4836 __u16 params, byte_count, data_count, param_offset, offset;
4837
Joe Perchesb6b38f72010-04-21 03:50:45 +00004838 cFYI(1, "In SetEOF");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004839SetEOFRetry:
4840 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4841 (void **) &pSMBr);
4842 if (rc)
4843 return rc;
4844
4845 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4846 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004847 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004848 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004849 name_len++; /* trailing null */
4850 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004851 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004852 name_len = strnlen(fileName, PATH_MAX);
4853 name_len++; /* trailing null */
4854 strncpy(pSMB->FileName, fileName, name_len);
4855 }
4856 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00004857 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004858 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07004859 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004860 pSMB->MaxSetupCount = 0;
4861 pSMB->Reserved = 0;
4862 pSMB->Flags = 0;
4863 pSMB->Timeout = 0;
4864 pSMB->Reserved2 = 0;
4865 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00004866 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004867 offset = param_offset + params;
Steve French790fe572007-07-07 19:25:05 +00004868 if (SetAllocation) {
Steve French50c2f752007-07-13 00:33:32 +00004869 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4870 pSMB->InformationLevel =
4871 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4872 else
4873 pSMB->InformationLevel =
4874 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4875 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004876 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4877 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004878 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004879 else
4880 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004881 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004882 }
4883
4884 parm_data =
4885 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4886 offset);
4887 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4888 pSMB->DataOffset = cpu_to_le16(offset);
4889 pSMB->SetupCount = 1;
4890 pSMB->Reserved3 = 0;
4891 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4892 byte_count = 3 /* pad */ + params + data_count;
4893 pSMB->DataCount = cpu_to_le16(data_count);
4894 pSMB->TotalDataCount = pSMB->DataCount;
4895 pSMB->ParameterCount = cpu_to_le16(params);
4896 pSMB->TotalParameterCount = pSMB->ParameterCount;
4897 pSMB->Reserved4 = 0;
4898 pSMB->hdr.smb_buf_length += byte_count;
4899 parm_data->FileSize = cpu_to_le64(size);
4900 pSMB->ByteCount = cpu_to_le16(byte_count);
4901 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4902 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004903 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00004904 cFYI(1, "SetPathInfo (file size) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004905
4906 cifs_buf_release(pSMB);
4907
4908 if (rc == -EAGAIN)
4909 goto SetEOFRetry;
4910
4911 return rc;
4912}
4913
4914int
Steve French50c2f752007-07-13 00:33:32 +00004915CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
Steve French4b18f2a2008-04-29 00:06:05 +00004916 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004917{
4918 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004919 char *data_offset;
4920 struct file_end_of_file_info *parm_data;
4921 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004922 __u16 params, param_offset, offset, byte_count, count;
4923
Joe Perchesb6b38f72010-04-21 03:50:45 +00004924 cFYI(1, "SetFileSize (via SetFileInfo) %lld",
4925 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07004926 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4927
Linus Torvalds1da177e2005-04-16 15:20:36 -07004928 if (rc)
4929 return rc;
4930
4931 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4932 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00004933
Linus Torvalds1da177e2005-04-16 15:20:36 -07004934 params = 6;
4935 pSMB->MaxSetupCount = 0;
4936 pSMB->Reserved = 0;
4937 pSMB->Flags = 0;
4938 pSMB->Timeout = 0;
4939 pSMB->Reserved2 = 0;
4940 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4941 offset = param_offset + params;
4942
Steve French50c2f752007-07-13 00:33:32 +00004943 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004944
4945 count = sizeof(struct file_end_of_file_info);
4946 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004947 /* BB find exact max SMB PDU from sess structure BB */
4948 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004949 pSMB->SetupCount = 1;
4950 pSMB->Reserved3 = 0;
4951 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4952 byte_count = 3 /* pad */ + params + count;
4953 pSMB->DataCount = cpu_to_le16(count);
4954 pSMB->ParameterCount = cpu_to_le16(params);
4955 pSMB->TotalDataCount = pSMB->DataCount;
4956 pSMB->TotalParameterCount = pSMB->ParameterCount;
4957 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4958 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00004959 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
4960 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004961 pSMB->DataOffset = cpu_to_le16(offset);
4962 parm_data->FileSize = cpu_to_le64(size);
4963 pSMB->Fid = fid;
Steve French790fe572007-07-07 19:25:05 +00004964 if (SetAllocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004965 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4966 pSMB->InformationLevel =
4967 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4968 else
4969 pSMB->InformationLevel =
4970 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00004971 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004972 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4973 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004974 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004975 else
4976 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004977 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004978 }
4979 pSMB->Reserved4 = 0;
4980 pSMB->hdr.smb_buf_length += byte_count;
4981 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French133672e2007-11-13 22:41:37 +00004982 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004983 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004984 cFYI(1, "Send error in SetFileInfo (SetFileSize) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004985 }
4986
Steve French50c2f752007-07-13 00:33:32 +00004987 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004988 since file handle passed in no longer valid */
4989
4990 return rc;
4991}
4992
Steve French50c2f752007-07-13 00:33:32 +00004993/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07004994 an open handle, rather than by pathname - this is awkward due to
4995 potential access conflicts on the open, but it is unavoidable for these
4996 old servers since the only other choice is to go from 100 nanosecond DCE
4997 time and resort to the original setpathinfo level which takes the ancient
4998 DOS time format with 2 second granularity */
4999int
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005000CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon,
5001 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005002{
5003 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005004 char *data_offset;
5005 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005006 __u16 params, param_offset, offset, byte_count, count;
5007
Joe Perchesb6b38f72010-04-21 03:50:45 +00005008 cFYI(1, "Set Times (via SetFileInfo)");
Steve Frenchcd634992005-04-28 22:41:10 -07005009 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5010
Linus Torvalds1da177e2005-04-16 15:20:36 -07005011 if (rc)
5012 return rc;
5013
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005014 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5015 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005016
Linus Torvalds1da177e2005-04-16 15:20:36 -07005017 params = 6;
5018 pSMB->MaxSetupCount = 0;
5019 pSMB->Reserved = 0;
5020 pSMB->Flags = 0;
5021 pSMB->Timeout = 0;
5022 pSMB->Reserved2 = 0;
5023 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5024 offset = param_offset + params;
5025
Steve French50c2f752007-07-13 00:33:32 +00005026 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005027
Steve French26f57362007-08-30 22:09:15 +00005028 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005029 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005030 /* BB find max SMB PDU from sess */
5031 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005032 pSMB->SetupCount = 1;
5033 pSMB->Reserved3 = 0;
5034 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5035 byte_count = 3 /* pad */ + params + count;
5036 pSMB->DataCount = cpu_to_le16(count);
5037 pSMB->ParameterCount = cpu_to_le16(params);
5038 pSMB->TotalDataCount = pSMB->DataCount;
5039 pSMB->TotalParameterCount = pSMB->ParameterCount;
5040 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5041 pSMB->DataOffset = cpu_to_le16(offset);
5042 pSMB->Fid = fid;
5043 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5044 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5045 else
5046 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5047 pSMB->Reserved4 = 0;
5048 pSMB->hdr.smb_buf_length += byte_count;
5049 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005050 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Steve French133672e2007-11-13 22:41:37 +00005051 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005052 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005053 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005054
Steve French50c2f752007-07-13 00:33:32 +00005055 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005056 since file handle passed in no longer valid */
5057
5058 return rc;
5059}
5060
Jeff Layton6d22f092008-09-23 11:48:35 -04005061int
5062CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon,
5063 bool delete_file, __u16 fid, __u32 pid_of_opener)
5064{
5065 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5066 char *data_offset;
5067 int rc = 0;
5068 __u16 params, param_offset, offset, byte_count, count;
5069
Joe Perchesb6b38f72010-04-21 03:50:45 +00005070 cFYI(1, "Set File Disposition (via SetFileInfo)");
Jeff Layton6d22f092008-09-23 11:48:35 -04005071 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5072
5073 if (rc)
5074 return rc;
5075
5076 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5077 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5078
5079 params = 6;
5080 pSMB->MaxSetupCount = 0;
5081 pSMB->Reserved = 0;
5082 pSMB->Flags = 0;
5083 pSMB->Timeout = 0;
5084 pSMB->Reserved2 = 0;
5085 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5086 offset = param_offset + params;
5087
5088 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5089
5090 count = 1;
5091 pSMB->MaxParameterCount = cpu_to_le16(2);
5092 /* BB find max SMB PDU from sess */
5093 pSMB->MaxDataCount = cpu_to_le16(1000);
5094 pSMB->SetupCount = 1;
5095 pSMB->Reserved3 = 0;
5096 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5097 byte_count = 3 /* pad */ + params + count;
5098 pSMB->DataCount = cpu_to_le16(count);
5099 pSMB->ParameterCount = cpu_to_le16(params);
5100 pSMB->TotalDataCount = pSMB->DataCount;
5101 pSMB->TotalParameterCount = pSMB->ParameterCount;
5102 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5103 pSMB->DataOffset = cpu_to_le16(offset);
5104 pSMB->Fid = fid;
5105 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5106 pSMB->Reserved4 = 0;
5107 pSMB->hdr.smb_buf_length += byte_count;
5108 pSMB->ByteCount = cpu_to_le16(byte_count);
5109 *data_offset = delete_file ? 1 : 0;
5110 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
5111 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005112 cFYI(1, "Send error in SetFileDisposition = %d", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005113
5114 return rc;
5115}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005116
5117int
Jeff Layton6fc000e2008-08-02 07:26:12 -04005118CIFSSMBSetPathInfo(const int xid, struct cifsTconInfo *tcon,
5119 const char *fileName, const FILE_BASIC_INFO *data,
5120 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005121{
5122 TRANSACTION2_SPI_REQ *pSMB = NULL;
5123 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5124 int name_len;
5125 int rc = 0;
5126 int bytes_returned = 0;
5127 char *data_offset;
5128 __u16 params, param_offset, offset, byte_count, count;
5129
Joe Perchesb6b38f72010-04-21 03:50:45 +00005130 cFYI(1, "In SetTimes");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005131
5132SetTimesRetry:
5133 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5134 (void **) &pSMBr);
5135 if (rc)
5136 return rc;
5137
5138 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5139 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05005140 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005141 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005142 name_len++; /* trailing null */
5143 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005144 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005145 name_len = strnlen(fileName, PATH_MAX);
5146 name_len++; /* trailing null */
5147 strncpy(pSMB->FileName, fileName, name_len);
5148 }
5149
5150 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005151 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005152 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005153 /* BB find max SMB PDU from sess structure BB */
5154 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005155 pSMB->MaxSetupCount = 0;
5156 pSMB->Reserved = 0;
5157 pSMB->Flags = 0;
5158 pSMB->Timeout = 0;
5159 pSMB->Reserved2 = 0;
5160 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005161 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005162 offset = param_offset + params;
5163 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5164 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5165 pSMB->DataOffset = cpu_to_le16(offset);
5166 pSMB->SetupCount = 1;
5167 pSMB->Reserved3 = 0;
5168 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5169 byte_count = 3 /* pad */ + params + count;
5170
5171 pSMB->DataCount = cpu_to_le16(count);
5172 pSMB->ParameterCount = cpu_to_le16(params);
5173 pSMB->TotalDataCount = pSMB->DataCount;
5174 pSMB->TotalParameterCount = pSMB->ParameterCount;
5175 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5176 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5177 else
5178 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5179 pSMB->Reserved4 = 0;
5180 pSMB->hdr.smb_buf_length += byte_count;
Steve French26f57362007-08-30 22:09:15 +00005181 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005182 pSMB->ByteCount = cpu_to_le16(byte_count);
5183 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5184 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005185 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005186 cFYI(1, "SetPathInfo (times) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005187
5188 cifs_buf_release(pSMB);
5189
5190 if (rc == -EAGAIN)
5191 goto SetTimesRetry;
5192
5193 return rc;
5194}
5195
5196/* Can not be used to set time stamps yet (due to old DOS time format) */
5197/* Can be used to set attributes */
5198#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5199 handling it anyway and NT4 was what we thought it would be needed for
5200 Do not delete it until we prove whether needed for Win9x though */
5201int
5202CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
5203 __u16 dos_attrs, const struct nls_table *nls_codepage)
5204{
5205 SETATTR_REQ *pSMB = NULL;
5206 SETATTR_RSP *pSMBr = NULL;
5207 int rc = 0;
5208 int bytes_returned;
5209 int name_len;
5210
Joe Perchesb6b38f72010-04-21 03:50:45 +00005211 cFYI(1, "In SetAttrLegacy");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005212
5213SetAttrLgcyRetry:
5214 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5215 (void **) &pSMBr);
5216 if (rc)
5217 return rc;
5218
5219 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5220 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005221 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005222 PATH_MAX, nls_codepage);
5223 name_len++; /* trailing null */
5224 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005225 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005226 name_len = strnlen(fileName, PATH_MAX);
5227 name_len++; /* trailing null */
5228 strncpy(pSMB->fileName, fileName, name_len);
5229 }
5230 pSMB->attr = cpu_to_le16(dos_attrs);
5231 pSMB->BufferFormat = 0x04;
5232 pSMB->hdr.smb_buf_length += name_len + 1;
5233 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5234 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5235 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005236 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005237 cFYI(1, "Error in LegacySetAttr = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005238
5239 cifs_buf_release(pSMB);
5240
5241 if (rc == -EAGAIN)
5242 goto SetAttrLgcyRetry;
5243
5244 return rc;
5245}
5246#endif /* temporarily unneeded SetAttr legacy function */
5247
Jeff Layton654cf142009-07-09 20:02:49 -04005248static void
5249cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5250 const struct cifs_unix_set_info_args *args)
5251{
5252 u64 mode = args->mode;
5253
5254 /*
5255 * Samba server ignores set of file size to zero due to bugs in some
5256 * older clients, but we should be precise - we use SetFileSize to
5257 * set file size and do not want to truncate file size to zero
5258 * accidently as happened on one Samba server beta by putting
5259 * zero instead of -1 here
5260 */
5261 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5262 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5263 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5264 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5265 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5266 data_offset->Uid = cpu_to_le64(args->uid);
5267 data_offset->Gid = cpu_to_le64(args->gid);
5268 /* better to leave device as zero when it is */
5269 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5270 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5271 data_offset->Permissions = cpu_to_le64(mode);
5272
5273 if (S_ISREG(mode))
5274 data_offset->Type = cpu_to_le32(UNIX_FILE);
5275 else if (S_ISDIR(mode))
5276 data_offset->Type = cpu_to_le32(UNIX_DIR);
5277 else if (S_ISLNK(mode))
5278 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5279 else if (S_ISCHR(mode))
5280 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5281 else if (S_ISBLK(mode))
5282 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5283 else if (S_ISFIFO(mode))
5284 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5285 else if (S_ISSOCK(mode))
5286 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5287}
5288
Linus Torvalds1da177e2005-04-16 15:20:36 -07005289int
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005290CIFSSMBUnixSetFileInfo(const int xid, struct cifsTconInfo *tcon,
5291 const struct cifs_unix_set_info_args *args,
5292 u16 fid, u32 pid_of_opener)
5293{
5294 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5295 FILE_UNIX_BASIC_INFO *data_offset;
5296 int rc = 0;
5297 u16 params, param_offset, offset, byte_count, count;
5298
Joe Perchesb6b38f72010-04-21 03:50:45 +00005299 cFYI(1, "Set Unix Info (via SetFileInfo)");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005300 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5301
5302 if (rc)
5303 return rc;
5304
5305 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5306 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5307
5308 params = 6;
5309 pSMB->MaxSetupCount = 0;
5310 pSMB->Reserved = 0;
5311 pSMB->Flags = 0;
5312 pSMB->Timeout = 0;
5313 pSMB->Reserved2 = 0;
5314 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5315 offset = param_offset + params;
5316
5317 data_offset = (FILE_UNIX_BASIC_INFO *)
5318 ((char *)(&pSMB->hdr.Protocol) + offset);
5319 count = sizeof(FILE_UNIX_BASIC_INFO);
5320
5321 pSMB->MaxParameterCount = cpu_to_le16(2);
5322 /* BB find max SMB PDU from sess */
5323 pSMB->MaxDataCount = cpu_to_le16(1000);
5324 pSMB->SetupCount = 1;
5325 pSMB->Reserved3 = 0;
5326 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5327 byte_count = 3 /* pad */ + params + count;
5328 pSMB->DataCount = cpu_to_le16(count);
5329 pSMB->ParameterCount = cpu_to_le16(params);
5330 pSMB->TotalDataCount = pSMB->DataCount;
5331 pSMB->TotalParameterCount = pSMB->ParameterCount;
5332 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5333 pSMB->DataOffset = cpu_to_le16(offset);
5334 pSMB->Fid = fid;
5335 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5336 pSMB->Reserved4 = 0;
5337 pSMB->hdr.smb_buf_length += byte_count;
5338 pSMB->ByteCount = cpu_to_le16(byte_count);
5339
5340 cifs_fill_unix_set_info(data_offset, args);
5341
5342 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
5343 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005344 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005345
5346 /* Note: On -EAGAIN error only caller can retry on handle based calls
5347 since file handle passed in no longer valid */
5348
5349 return rc;
5350}
5351
5352int
Jeff Layton01ea95e2009-07-09 20:02:49 -04005353CIFSSMBUnixSetPathInfo(const int xid, struct cifsTconInfo *tcon, char *fileName,
5354 const struct cifs_unix_set_info_args *args,
5355 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005356{
5357 TRANSACTION2_SPI_REQ *pSMB = NULL;
5358 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5359 int name_len;
5360 int rc = 0;
5361 int bytes_returned = 0;
5362 FILE_UNIX_BASIC_INFO *data_offset;
5363 __u16 params, param_offset, offset, count, byte_count;
5364
Joe Perchesb6b38f72010-04-21 03:50:45 +00005365 cFYI(1, "In SetUID/GID/Mode");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005366setPermsRetry:
5367 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5368 (void **) &pSMBr);
5369 if (rc)
5370 return rc;
5371
5372 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5373 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005374 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005375 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005376 name_len++; /* trailing null */
5377 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005378 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005379 name_len = strnlen(fileName, PATH_MAX);
5380 name_len++; /* trailing null */
5381 strncpy(pSMB->FileName, fileName, name_len);
5382 }
5383
5384 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005385 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005386 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005387 /* BB find max SMB PDU from sess structure BB */
5388 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005389 pSMB->MaxSetupCount = 0;
5390 pSMB->Reserved = 0;
5391 pSMB->Flags = 0;
5392 pSMB->Timeout = 0;
5393 pSMB->Reserved2 = 0;
5394 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005395 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005396 offset = param_offset + params;
5397 data_offset =
5398 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5399 offset);
5400 memset(data_offset, 0, count);
5401 pSMB->DataOffset = cpu_to_le16(offset);
5402 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5403 pSMB->SetupCount = 1;
5404 pSMB->Reserved3 = 0;
5405 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5406 byte_count = 3 /* pad */ + params + count;
5407 pSMB->ParameterCount = cpu_to_le16(params);
5408 pSMB->DataCount = cpu_to_le16(count);
5409 pSMB->TotalParameterCount = pSMB->ParameterCount;
5410 pSMB->TotalDataCount = pSMB->DataCount;
5411 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5412 pSMB->Reserved4 = 0;
5413 pSMB->hdr.smb_buf_length += byte_count;
Steve French50c2f752007-07-13 00:33:32 +00005414
Jeff Layton654cf142009-07-09 20:02:49 -04005415 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005416
5417 pSMB->ByteCount = cpu_to_le16(byte_count);
5418 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5419 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005420 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005421 cFYI(1, "SetPathInfo (perms) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005422
Steve French0d817bc2008-05-22 02:02:03 +00005423 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005424 if (rc == -EAGAIN)
5425 goto setPermsRetry;
5426 return rc;
5427}
5428
Steve French50c2f752007-07-13 00:33:32 +00005429int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07005430 const int notify_subdirs, const __u16 netfid,
Steve French50c2f752007-07-13 00:33:32 +00005431 __u32 filter, struct file *pfile, int multishot,
Steve French167a2512005-08-24 20:03:11 -07005432 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005433{
5434 int rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00005435 struct smb_com_transaction_change_notify_req *pSMB = NULL;
5436 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07005437 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005438 int bytes_returned;
5439
Joe Perchesb6b38f72010-04-21 03:50:45 +00005440 cFYI(1, "In CIFSSMBNotify for file handle %d", (int)netfid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005441 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00005442 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005443 if (rc)
5444 return rc;
5445
5446 pSMB->TotalParameterCount = 0 ;
5447 pSMB->TotalDataCount = 0;
5448 pSMB->MaxParameterCount = cpu_to_le32(2);
5449 /* BB find exact data count max from sess structure BB */
5450 pSMB->MaxDataCount = 0; /* same in little endian or be */
Steve French0a4b92c2006-01-12 15:44:21 -08005451/* BB VERIFY verify which is correct for above BB */
5452 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
5453 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
5454
Linus Torvalds1da177e2005-04-16 15:20:36 -07005455 pSMB->MaxSetupCount = 4;
5456 pSMB->Reserved = 0;
5457 pSMB->ParameterOffset = 0;
5458 pSMB->DataCount = 0;
5459 pSMB->DataOffset = 0;
5460 pSMB->SetupCount = 4; /* single byte does not need le conversion */
5461 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
5462 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00005463 if (notify_subdirs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005464 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
5465 pSMB->Reserved2 = 0;
5466 pSMB->CompletionFilter = cpu_to_le32(filter);
5467 pSMB->Fid = netfid; /* file handle always le */
5468 pSMB->ByteCount = 0;
5469
5470 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00005471 (struct smb_hdr *)pSMBr, &bytes_returned,
5472 CIFS_ASYNC_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005473 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005474 cFYI(1, "Error in Notify = %d", rc);
Steve Frenchff5dbd92005-08-24 17:10:36 -07005475 } else {
5476 /* Add file to outstanding requests */
Steve French50c2f752007-07-13 00:33:32 +00005477 /* BB change to kmem cache alloc */
Robert P. J. Day5cbded52006-12-13 00:35:56 -08005478 dnotify_req = kmalloc(
Steve French47c786e2005-10-11 20:03:18 -07005479 sizeof(struct dir_notify_req),
5480 GFP_KERNEL);
Steve French790fe572007-07-07 19:25:05 +00005481 if (dnotify_req) {
Steve French47c786e2005-10-11 20:03:18 -07005482 dnotify_req->Pid = pSMB->hdr.Pid;
5483 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
5484 dnotify_req->Mid = pSMB->hdr.Mid;
5485 dnotify_req->Tid = pSMB->hdr.Tid;
5486 dnotify_req->Uid = pSMB->hdr.Uid;
5487 dnotify_req->netfid = netfid;
5488 dnotify_req->pfile = pfile;
5489 dnotify_req->filter = filter;
5490 dnotify_req->multishot = multishot;
5491 spin_lock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005492 list_add_tail(&dnotify_req->lhead,
Steve French47c786e2005-10-11 20:03:18 -07005493 &GlobalDnotifyReqList);
5494 spin_unlock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005495 } else
Steve French47c786e2005-10-11 20:03:18 -07005496 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005497 }
5498 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00005499 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005500}
Jeff Layton31c05192010-02-10 16:18:26 -05005501
Linus Torvalds1da177e2005-04-16 15:20:36 -07005502#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05005503/*
5504 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
5505 * function used by listxattr and getxattr type calls. When ea_name is set,
5506 * it looks for that attribute name and stuffs that value into the EAData
5507 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
5508 * buffer. In both cases, the return value is either the length of the
5509 * resulting data or a negative error code. If EAData is a NULL pointer then
5510 * the data isn't copied to it, but the length is returned.
5511 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005512ssize_t
5513CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05005514 const unsigned char *searchName, const unsigned char *ea_name,
5515 char *EAData, size_t buf_size,
5516 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005517{
5518 /* BB assumes one setup word */
5519 TRANSACTION2_QPI_REQ *pSMB = NULL;
5520 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5521 int rc = 0;
5522 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05005523 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005524 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00005525 struct fea *temp_fea;
5526 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05005527 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005528 __u16 params, byte_count, data_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005529
Joe Perchesb6b38f72010-04-21 03:50:45 +00005530 cFYI(1, "In Query All EAs path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005531QAllEAsRetry:
5532 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5533 (void **) &pSMBr);
5534 if (rc)
5535 return rc;
5536
5537 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05005538 list_len =
Steve French50c2f752007-07-13 00:33:32 +00005539 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005540 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05005541 list_len++; /* trailing null */
5542 list_len *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005543 } else { /* BB improve the check for buffer overruns BB */
Jeff Layton6e462b92010-02-10 16:18:26 -05005544 list_len = strnlen(searchName, PATH_MAX);
5545 list_len++; /* trailing null */
5546 strncpy(pSMB->FileName, searchName, list_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005547 }
5548
Jeff Layton6e462b92010-02-10 16:18:26 -05005549 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005550 pSMB->TotalDataCount = 0;
5551 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005552 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05005553 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005554 pSMB->MaxSetupCount = 0;
5555 pSMB->Reserved = 0;
5556 pSMB->Flags = 0;
5557 pSMB->Timeout = 0;
5558 pSMB->Reserved2 = 0;
5559 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005560 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005561 pSMB->DataCount = 0;
5562 pSMB->DataOffset = 0;
5563 pSMB->SetupCount = 1;
5564 pSMB->Reserved3 = 0;
5565 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5566 byte_count = params + 1 /* pad */ ;
5567 pSMB->TotalParameterCount = cpu_to_le16(params);
5568 pSMB->ParameterCount = pSMB->TotalParameterCount;
5569 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5570 pSMB->Reserved4 = 0;
5571 pSMB->hdr.smb_buf_length += byte_count;
5572 pSMB->ByteCount = cpu_to_le16(byte_count);
5573
5574 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5575 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5576 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005577 cFYI(1, "Send error in QueryAllEAs = %d", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05005578 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005579 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05005580
5581
5582 /* BB also check enough total bytes returned */
5583 /* BB we need to improve the validity checking
5584 of these trans2 responses */
5585
5586 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5587 if (rc || (pSMBr->ByteCount < 4)) {
5588 rc = -EIO; /* bad smb */
5589 goto QAllEAsOut;
5590 }
5591
5592 /* check that length of list is not more than bcc */
5593 /* check that each entry does not go beyond length
5594 of list */
5595 /* check that each element of each entry does not
5596 go beyond end of list */
5597 /* validate_trans2_offsets() */
5598 /* BB check if start of smb + data_offset > &bcc+ bcc */
5599
5600 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5601 ea_response_data = (struct fealist *)
5602 (((char *) &pSMBr->hdr.Protocol) + data_offset);
5603
Jeff Layton6e462b92010-02-10 16:18:26 -05005604 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesb6b38f72010-04-21 03:50:45 +00005605 cFYI(1, "ea length %d", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05005606 if (list_len <= 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005607 cFYI(1, "empty EA list returned from server");
Jeff Laytonf0d38682010-02-10 16:18:26 -05005608 goto QAllEAsOut;
5609 }
5610
Jeff Layton0cd126b2010-02-10 16:18:26 -05005611 /* make sure list_len doesn't go past end of SMB */
5612 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + BCC(&pSMBr->hdr);
5613 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005614 cFYI(1, "EA list appears to go beyond SMB");
Jeff Layton0cd126b2010-02-10 16:18:26 -05005615 rc = -EIO;
5616 goto QAllEAsOut;
5617 }
5618
Jeff Laytonf0d38682010-02-10 16:18:26 -05005619 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05005620 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005621 temp_fea = ea_response_data->list;
5622 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05005623 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00005624 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005625 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05005626
Jeff Layton6e462b92010-02-10 16:18:26 -05005627 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005628 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05005629 /* make sure we can read name_len and value_len */
5630 if (list_len < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005631 cFYI(1, "EA entry goes beyond length of list");
Jeff Layton0cd126b2010-02-10 16:18:26 -05005632 rc = -EIO;
5633 goto QAllEAsOut;
5634 }
5635
5636 name_len = temp_fea->name_len;
5637 value_len = le16_to_cpu(temp_fea->value_len);
5638 list_len -= name_len + 1 + value_len;
5639 if (list_len < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005640 cFYI(1, "EA entry goes beyond length of list");
Jeff Layton0cd126b2010-02-10 16:18:26 -05005641 rc = -EIO;
5642 goto QAllEAsOut;
5643 }
5644
Jeff Layton31c05192010-02-10 16:18:26 -05005645 if (ea_name) {
5646 if (strncmp(ea_name, temp_ptr, name_len) == 0) {
5647 temp_ptr += name_len + 1;
5648 rc = value_len;
5649 if (buf_size == 0)
5650 goto QAllEAsOut;
5651 if ((size_t)value_len > buf_size) {
5652 rc = -ERANGE;
5653 goto QAllEAsOut;
5654 }
5655 memcpy(EAData, temp_ptr, value_len);
5656 goto QAllEAsOut;
5657 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05005658 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05005659 /* account for prefix user. and trailing null */
5660 rc += (5 + 1 + name_len);
5661 if (rc < (int) buf_size) {
5662 memcpy(EAData, "user.", 5);
5663 EAData += 5;
5664 memcpy(EAData, temp_ptr, name_len);
5665 EAData += name_len;
5666 /* null terminate name */
5667 *EAData = 0;
5668 ++EAData;
5669 } else if (buf_size == 0) {
5670 /* skip copy - calc size only */
5671 } else {
5672 /* stop before overrun buffer */
5673 rc = -ERANGE;
5674 break;
5675 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05005676 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05005677 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005678 temp_fea = (struct fea *)temp_ptr;
5679 }
5680
Jeff Layton31c05192010-02-10 16:18:26 -05005681 /* didn't find the named attribute */
5682 if (ea_name)
5683 rc = -ENODATA;
5684
Jeff Laytonf0d38682010-02-10 16:18:26 -05005685QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00005686 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005687 if (rc == -EAGAIN)
5688 goto QAllEAsRetry;
5689
5690 return (ssize_t)rc;
5691}
5692
Linus Torvalds1da177e2005-04-16 15:20:36 -07005693int
5694CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00005695 const char *ea_name, const void *ea_value,
5696 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5697 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005698{
5699 struct smb_com_transaction2_spi_req *pSMB = NULL;
5700 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5701 struct fealist *parm_data;
5702 int name_len;
5703 int rc = 0;
5704 int bytes_returned = 0;
5705 __u16 params, param_offset, byte_count, offset, count;
5706
Joe Perchesb6b38f72010-04-21 03:50:45 +00005707 cFYI(1, "In SetEA");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005708SetEARetry:
5709 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5710 (void **) &pSMBr);
5711 if (rc)
5712 return rc;
5713
5714 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5715 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005716 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005717 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005718 name_len++; /* trailing null */
5719 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005720 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005721 name_len = strnlen(fileName, PATH_MAX);
5722 name_len++; /* trailing null */
5723 strncpy(pSMB->FileName, fileName, name_len);
5724 }
5725
5726 params = 6 + name_len;
5727
5728 /* done calculating parms using name_len of file name,
5729 now use name_len to calculate length of ea name
5730 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00005731 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005732 name_len = 0;
5733 else
Steve French50c2f752007-07-13 00:33:32 +00005734 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005735
Steve Frenchdae5dbd2007-12-30 23:49:57 +00005736 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005737 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005738 /* BB find max SMB PDU from sess */
5739 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005740 pSMB->MaxSetupCount = 0;
5741 pSMB->Reserved = 0;
5742 pSMB->Flags = 0;
5743 pSMB->Timeout = 0;
5744 pSMB->Reserved2 = 0;
5745 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005746 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005747 offset = param_offset + params;
5748 pSMB->InformationLevel =
5749 cpu_to_le16(SMB_SET_FILE_EA);
5750
5751 parm_data =
5752 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5753 offset);
5754 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5755 pSMB->DataOffset = cpu_to_le16(offset);
5756 pSMB->SetupCount = 1;
5757 pSMB->Reserved3 = 0;
5758 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5759 byte_count = 3 /* pad */ + params + count;
5760 pSMB->DataCount = cpu_to_le16(count);
5761 parm_data->list_len = cpu_to_le32(count);
5762 parm_data->list[0].EA_flags = 0;
5763 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08005764 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005765 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00005766 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00005767 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005768 parm_data->list[0].name[name_len] = 0;
5769 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5770 /* caller ensures that ea_value_len is less than 64K but
5771 we need to ensure that it fits within the smb */
5772
Steve French50c2f752007-07-13 00:33:32 +00005773 /*BB add length check to see if it would fit in
5774 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00005775 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5776 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00005777 memcpy(parm_data->list[0].name+name_len+1,
5778 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005779
5780 pSMB->TotalDataCount = pSMB->DataCount;
5781 pSMB->ParameterCount = cpu_to_le16(params);
5782 pSMB->TotalParameterCount = pSMB->ParameterCount;
5783 pSMB->Reserved4 = 0;
5784 pSMB->hdr.smb_buf_length += byte_count;
5785 pSMB->ByteCount = cpu_to_le16(byte_count);
5786 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5787 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005788 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005789 cFYI(1, "SetPathInfo (EA) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005790
5791 cifs_buf_release(pSMB);
5792
5793 if (rc == -EAGAIN)
5794 goto SetEARetry;
5795
5796 return rc;
5797}
5798
5799#endif